实例讲解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 转码

相关文章
相关标签/搜索