成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6 Generator與異步的同步書寫

andycall / 3065人閱讀

摘要:返回值是一個對象,它的第一個屬性是后面表達式的值或者的值第二個屬性表示函數(shù)是否執(zhí)行完成。真正的業(yè)務邏輯確實是用同步的方式寫的。

開始前

我們從來沒有停止過對javascript語言異步調用方式的改造,我們一直都想用像java那樣同步的方式去寫異步,盡管Promise可以讓我們將異步回調添加到then方法中,但是這種調用方式仍然不那么優(yōu)雅,es6 中新增加了generator,我們可以通過他的特性來實現(xiàn)異步任務更加優(yōu)雅的書寫方式。

協(xié)程介紹

協(xié)程其實和線程,進程是沒有關系的,它不是操作系統(tǒng)為我們提供的api接口,而是通過編程語言或者匯編語言對程序上下文、程序棧來操作實現(xiàn)的。一個線程里面可以包含多個協(xié)程,線程的調度是由操作體統(tǒng)來決定的,協(xié)程的調度是由用戶來決定的。操作系統(tǒng)對其一無所知,因為可以由用戶來調度,所以用來執(zhí)行協(xié)作式的任務特別方便。(注意這里是方便,因為能通過協(xié)程解決的問題,通過線程和進程也可以解決,但是復雜)

Generator介紹

Generator 是協(xié)程在es6中的實現(xiàn)。它在es6中是一個函數(shù),這個函數(shù)可以分階段執(zhí)行,也就是說我們可以在這個函數(shù)中的某個位置選擇交出當前線程的執(zhí)行權限,也可以在當前函數(shù)外面的某個位置選擇將權限再交回這個函數(shù),讓它繼續(xù)執(zhí)行,這種調度完全由用戶決定。在es6中協(xié)程函數(shù)是這樣的

function* gen(p) {
    var a = yield p + 1;  //1
    var b = yield p + 2;  //2
    return b;  //3
}

var g = gen(1);
g.next();  //{value: 2, done: false}
g.next();  //{value: 3, done: false}
g.next();  //{value: undefined, done: true}

通過 var g = gen(1); 僅僅是創(chuàng)建了一個迭代器,函數(shù) gen 里面的內容并沒有執(zhí)行函數(shù)體的執(zhí)行時由第一個 g.next(); 開始的 并且將 yield 所在那那條語句執(zhí)行完后就會返回結果。而后面的語句并沒有執(zhí)行。返回值是一個對象,它的第一個屬性是 yield 后面表達式的值 (p+1或者p+2的值);第二個屬性表示Generator函數(shù)是否執(zhí)行完成。這里我們通過 yield 執(zhí)行權限交出去,通過 next 將權限返回。

function* gen(p) {
    var a = yield p + 1;  //1
    var b = yield a + 1;  //2 注意這里是用到了 a
    return b;
}
var g = gen(1);
g.next();  //{value: 2, done: false}
g.next();  //{value: NaN, done: false} 這里的值是 NaN
g.next();  //{value: undefined, done: true}

g.next();  //{value: 2, done: false}
g.next(2);  //{value: 3, done: false}
g.next(6);  //{value: 6, done: true}

注意這里 //1 處 //2 處 var a = yield p + 1;這條賦值語句中 a 的值并不是 p + 1的值。這條語句只是一種寫法,這里 a 的值是我們在第二個 next 中傳入的 2 這個很重要 b 的值也是我們在第三個 next 中傳入的 6

Generator 的重要特性

由上面的內容我們總結 3 個關于 Generator 的重要特性

1 通過 yield 交出執(zhí)行權限,通過 next 返回執(zhí)行權限
2 調用 next 會得到一個返回值,這個值里面包含了 yield 后面的表達式的執(zhí)行結果
3 我們可以通過給 next 傳遞參數(shù),并且可以在 Generator 函數(shù)中通過上面所寫的特殊方式來引用

利用 Generator 的特性來實現(xiàn)異步代碼的同步書寫

我們來模擬一個異步函數(shù)

function post(url, callback) {
    setTimeout(function() {
        var data = { //模擬異步處理結果
            url:url,
            value:10
        };
        callback(data);
    }, 1000);
}

post("http://_ivenj",function(data){
    console.log(data.url);  // http://_ivenj
    console.log(data.value);  //10
});

對應上面的這個異步函數(shù)我想通過 Generator 來這樣用

function* gen(url) {
    var data = yield post(url);  //1
    console.log(data.url);
    console.log(data.value);
}
var g = gen("http://_ivenj");
var resultG = g.next();
g.next(resultG.value);

是的,這樣寫漂亮多了,很像 java 的同步寫法。不同之處就是多了個 yield* ,這個無傷大雅。當然以上這樣用肯定是不行的。因為 post 畢竟是個異步方法。沒有返回值.如果不能實現(xiàn)這樣的寫法我這半天就是在扯淡,所以通過包裝是可以實現(xiàn)的。

通過以下兩點可以實現(xiàn)以上的書寫方式

(1)我有一篇文章 react 實踐之 redux applyMiddleware方法詳解 中介紹了柯里化(Currying)這篇文章雖然是寫react的但是柯里化是獨立的,這里就要利用柯里化的思想

(2)我們要在回調中調用 next 來繼續(xù)執(zhí)行,(這里有人會想不是不用回調了么,怎么還用,請繼續(xù)看。。。)

我們要對 post 的調用形式進行包裝

function kPost(url) {
    return function(callback) {
        post(url, callback);
    }
}

通過這個包裝,我們就能保證調用 kPost 就會同步的得到一個返回值

function* gen(url) {
    var data = yield kPost(url);  //1
    console.log(data.url);
    console.log(data.value);
}
//這里執(zhí)行方式會不同
var g = gen("http://_ivenj");
//啟動任務
var resultG1 = g.next();
var value_resultG1 = resultG1.value; //resultG1.value 一定是一個函數(shù),因為我們包裝了
value_resultG1(function(data){
    g.next(data);  //通過在異步的回調中調用 next 并傳遞值來確保依賴異步結果的代碼能正確執(zhí)行
});

下面就是整體代碼,是上面的片段組合,請你粘貼到瀏覽器控制臺,或者用node運行,就會看到想要的結果

function post(url, callback) {
    setTimeout(function() {
        var data = { //模擬異步處理結果
            url:url,
            value:10
        };
        callback(data);
    }, 1000);
}
function kPost(url) {
    return function(callback) {
        post(url, callback);
    }
}
function* gen(url) {
    var data = yield kPost(url);  //1
    console.log(data.url);
    console.log(data.value);
}
//這里執(zhí)行方式會不同
var g = gen("http://_ivenj");
//啟動任務
var resultG1 = g.next();
var value_resultG1 = resultG1.value; //resultG1.value 一定是一個函數(shù),因為我們包裝了
value_resultG1(function(data){
    g.next(data);
});

有人會說,怎么不就是將異步回調轉移出來了么,還要寫回調。這說明你還沒有真正體會個中之奧妙。我們會發(fā)現(xiàn) 我們寫的異步

value_resultG1(function(data){
    g.next(data);
});

僅僅是調用了 next 進行了結果的傳遞,這里面有共同之處,不管是哪一種異步,我們都只傳遞值。大家的處理都是一樣的。真正的業(yè)務邏輯確實是用同步的方式寫的。那么,我們可以將共同的地方提取出來,寫一個通用的函數(shù)去執(zhí)行這個傳值操作,這樣,我們完全就告別了異步,再也看不到了,好開心。co.js就是一個這種generator的執(zhí)行庫。使用它是我們只需要將我們的 gen 傳遞給它像這樣 co(gen) 是的就這樣。下面我們自己寫一個 co

Generator執(zhí)行器

function co(taskDef) {
    //獲取迭代器  類似 java 中的外柄迭代子
    var task = taskDef();
    //開始任務
    var result = task.next();
    //調用next的遞歸函數(shù)
    function step() {
        if (!result.done) {  //如果generator沒有執(zhí)行完
            if (typeof result.value === "function") {
                result.value(function(err, data) {
                    if (err) {
                        result = task.throw(err);
                        return;
                    }
                    result = task.next(data);  //向后傳遞當前異步處理結果
                    step();  //遞歸執(zhí)行
                });
            } else {
                result = task.next(result.value);  //如果執(zhí)行完了就傳遞值
                step();  //遞歸執(zhí)行
            }

        }
    }
    // 啟動遞歸函數(shù)
    step();
}

通過 co 執(zhí)行的完整代碼

function post(url, callback) {
    setTimeout(function() {
        var data = { //模擬異步處理結果
            url:url,
            value:10
        };
        callback(data);
    }, 1000);
}
function kPost(url) {
    return function(callback) {
        post(url, callback);
    }
}
function gen(url) {
    return function* () {
        var data = yield kPost(url);  //1
        console.log(data.url);
        console.log(data.value);
    }
}
function co(taskDef) {
    var task = taskDef();
    //開始任務
    var result = task.next();
    // 調用next的遞歸函數(shù)
    function step() {
        if (!result.done) {  //如果generator沒有執(zhí)行完
            if (typeof result.value === "function") {
                result.value(function(err, data) {
                    if (err) {
                        result = task.throw(err);
                        return;
                    }
                    result = task.next(data);  //向后傳遞當前異步處理結果
                    step();  //遞歸執(zhí)行
                });
            } else {
                result = task.next(result.value);  //如果執(zhí)行完了就傳遞值
                step();  //遞歸執(zhí)行
            }

        }
    }
    // 啟動遞歸函數(shù)
    step();
}
    
co(gen("http://_ivenj")); //調用方式就是這么簡單

以上代碼執(zhí)行 1s 后會拋出一個異常,并且正確打印{url: "http://_ivenj", value: 10},聰明的你一定知道為什么會拋出異常!!!

到這里已經說明白了,并且也說完了,你會想是不是把異步包裝成Promise也可以呢,答案是肯定的,柯里化的思想只是一種實現(xiàn)方式,Promise 也是一種,你可以自己去琢磨,co.js 就是將兩種方式都實現(xiàn)了的一個執(zhí)行器。es7 中從語言層面對 Generator 進行了包裝,在es7 中我們可以使用 asyncawait更優(yōu)雅的實現(xiàn)類似java的順序書寫方式,asyncawaitGenerator的語法糖,在es7中內置了執(zhí)行器。別人都說是終極方案。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/83918.html

相關文章

  • Generator同步代碼書寫異步情懷

    摘要:調用方法執(zhí)行到后暫停,內部環(huán)境被保存,執(zhí)行返回一個對象,為的執(zhí)行結果,表示迭代器是否完成。當?shù)魍瓿珊?,為,為的值,繼續(xù)執(zhí)行,將為執(zhí)行原理回到開頭的例子,給我們提供了直觀的寫法來處理異步回調,它讓代碼邏輯非常清晰。 編者按:看完本文,你能對ES6的Generator有一個很好的理解,輕松地以同步的方式寫異步代碼,也能初步理解到TJ大神的co框架的原理。 前言:ES6在2015年6月正...

    hightopo 評論0 收藏0
  • 【Web全棧課程三】ES6特性介紹(下)

    摘要:示例運行函數(shù)彈出彈出函數(shù)接收參數(shù),返回值。其中,返回一個對象,是的返回值,代表函數(shù)是否執(zhí)行完成。 ES6特性介紹(下) ES6新的標準,新的語法特征:1、變量/賦值2、函數(shù)3、數(shù)組/json4、字符串5、面向對象6、Promise7、generator8、ES7:async/await 《【Web全棧課程二】ES6特性介紹(上)》見:https://segmentfault.com/a...

    wangshijun 評論0 收藏0
  • 深入前端-JavaScript異步編程

    摘要:缺點無法取消當處于狀態(tài)時,無法得知目前進展到哪一個階段錯誤不能被生成器什么是函數(shù)是提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同函數(shù)有多種理解角度。 JavaScript的執(zhí)行機制在上篇文章中進行了深入的探討,那么既然是一門單線程語言,如何進行良好體驗的異步編程呢 回調函數(shù)Callbacks 當程序跑起來時,一般情況下,應用程序(application program)會時常通...

    2json 評論0 收藏0
  • 深入前端-JavaScript異步編程

    摘要:缺點無法取消當處于狀態(tài)時,無法得知目前進展到哪一個階段錯誤不能被生成器什么是函數(shù)是提供的一種異步編程解決方案,語法行為與傳統(tǒng)函數(shù)完全不同函數(shù)有多種理解角度。 JavaScript的執(zhí)行機制在上篇文章中進行了深入的探討,那么既然是一門單線程語言,如何進行良好體驗的異步編程呢 回調函數(shù)Callbacks 當程序跑起來時,一般情況下,應用程序(application program)會時常通...

    raise_yang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<