實例講解async的generator實現

async是es6提出的一種新的異步語法. 一開始es爲了解決異步,使用的是promise, 但看到滿屏的then以後,就感受本身傻逼了. 後來提出了generator, 在底層實現了一個異步的模式, 但須要手動執行. 關於如何使用generator,能夠參考,how to use generator. 本文這裏,不探討怎麼使用generato. 而是,若是使用generator和promise 構造出async的表達.es6

簡單異步實現

通常異步的寫法就是,傳回調嘛,好比:ajax

var ajax = function(url,cb){
    // send url
    // get res
    ...
    cb(JSON.parse(result))
}

這樣,應該最容易寫成callback hell. 而後咱們引入: generatorexpress

function *main() {
    var result1 = yield ajax( "http://some.url.1" );
    var data = JSON.parse( result1 );

    var result2 = yield ajax( "http://some.url.2?id=" + data.id );
    var resp = JSON.parse( result2 );
}

var async = main();
async.next();

function ajax(url){
    // send url
    async.next(res);
}

僞代碼的格式如上所述. 這裏,須要主意一個點. 若是,你沒有在next()中傳入res,like async.next(). 那麼,裏面result1和result2得到的結果就是undefined.
上面就是基本的generator異步. 那若是使用generator來模擬async呢?
這估計得解釋一下async出現的緣由promise

async why?

根據上面的解析,咱們能夠了解到, 使用next 執行語句時, 只能執行yield後面的表達式. 這樣形成的結果就是,不能parallel異步呀. 這樣限制性仍是很大的。因此,爲了解決這個問題,使用到es6提出的Promise對象來進行補充.
這裏,增長一個限定規則,即,ajax拉取返回的必須是一個promise對象.babel

function ajax(url){
    return new Promise(function(res,rej){
        send(url,function(result){
            res(result)
        })
    })
}

咱們再補充一下,若是使用generator來對promise進行tricky異步

function runGenerator(g) {
    var it = g(), ret;
    (function iterate(val){
        ret = it.next( val );
        if (!ret.done) {
            // 檢查是否已經then完成
            if ("then" in ret.value) {
                // 這一句很關鍵
                ret.value.then( iterate );
            }
            else {
                // 同步回調的trick
                setTimeout( function(){
                    iterate( ret.value );
                }, 0 );
            }
        }
    })();
}

OK, 這樣, 咱們就能夠在async裏面,使用同步的寫法,來表明異步的操做了.async

runGenerator(function* (){
    var result = yield new Promise(function(res,rej){
        setTimeout(function(){
            res('ok');
        },1000)
    });
})

因爲這裏要求的是使用promise, 那麼,咱們使用Promise.all([xx,xx]) 也是合情合理的. 這樣就能夠完美的解決掉--並行異步發送。url

runGenerator(function* (){
    yield Promise.all([ajax('http://villainhr.com'),ajax('http://villainhr.com')])
})

對比與,使用async的結構:code

(async function(){
    await Promise.all([ajax('http://villainhr.com'),ajax('http://villainhr.com')]);
})();

是否是感受一毛同樣呢? 不過在實際上操做中, async 還必須對new Promise進行兼容處理. 若是其餘人直接傳入一個expression, 你也必須保證他是可行的.
在babel中,講的其實也是這樣一個邏輯:orm

// In

async function foo() {
  await bar();
}
// Out

var _asyncToGenerator = function (fn) {
  ...
};
var foo = _asyncToGenerator(function* () {
  yield bar();
});

具體參考: babel es6 轉碼

相關文章
相關標籤/搜索