1

接着来说,generator生成器函数:看似同步的异步流程控制风格。

基础部分可以看一下阮一峰老师的 生成器函数的概念了解一下。

ECMAScript 6 入门 生成器

这里只做一些 生成器函数配合promise的高级使用。

在生成器函数中可以 同步的使用try catch来捕获错误。

生成器中可以使用yield 来等待 异步promise的返回,这样我们配合使用就可以 同步的来监听 异步任务里的错误。

支持Promsie的Generator Runner

如何自动从执行到结束一个生成器函数,asynquence 这个库里的runner()做了实现,现在我们来实现一个自己简易版本,run(...)

function run(gen){
    var args = [].slice.call(arguments,1);//不包含第一个之后的参数
    var it = gen.apply(this,args);//用当前上下文 还有args参数初始化生成器
    return Prommise.resolve().then(function handleNext(value){
        var next = it.next(value);//对下一个yield出的值运行
        return (function handleResult(next){
            if(next.done){//如果迭代到最后,生成器函数运行完毕
                return next.value;
            }else{//未运行完毕
                //next.value的值不一定是promsie,有可能是个立即值,所以通过promise.resolve()统一转成异步操作
                return Promise.resolve(next.value).then(
                        handleNext,//成功就回复异步循环,把决议的值发回生成器
                        function handleErr(err){
                            //如果value是 被拒绝的promise,就把错误传回生成器进行出错处理
                            //[https://www.axihe.com/api/js-es/ob-generator/throw.html](https://www.axihe.com/api/js-es/ob-generator/throw.html)
                            //it.throw(err)类似it.next  也会继续往下走,处理错误,返回 next对象包含done和value
                            return Promise.resolve(it.throw(err)).then(handleResult)    
                        }
                )
            }
        })(next)
    })
    
}

//测试调用
        function foo(b) {
            return request(b);
        }
        function request(b) {
            return new Promise(function (resolve, reject) {
                setTimeout(function () {
                    if (b) {
                        resolve('100')
                    } else {
                        reject('200')
                    }
                }, 2000)
            })
        }
        function *main() {
            try {
                var texts = yield foo();
                console.log(texts)
                var text = yield foo(true);
                console.log(text)

            } catch (err) {
                console.error(err);
            }
            var text = yield foo(true);
            console.log(text)
            return 40;
        }
console.log(run(main).then(function (v) { console.log(v) }))

这种自动运行run的方式,它会自动异步运行你传给它的生成器。

这种模式看起来是不是很眼熟,这就是async与await的前身
ES7的 async和await如下

function foo(x,y){
    return request('http://...')
}
async function main(){
    try{
        var text = await foo(1,51);
        console.log(text)
    }catch(err){
        console.error(err)
    }
}
main()

使用async关键词修饰。

生成器中promise的并发。

使用生成器实现异步的方法全部要点在于创建简单,顺序,看似同步的代码,将异步的细节尽可能的隐藏起来。

function bar(url1,url2){
    return Promise.all([
        request(url1),
        request(url2)
    ])
}
function *foo(){
    var results = yield bar('http://...1','http://...2');
    const [r1,r2] = results;
    var r3 = request('http://...3'+r1+r2)
    console.log(r3)
}

//更高级的用法,组合promise 的api
function bar(){
    Promise.all([baz(...).then(...),Promise.race([...])]).then(...)
}

像bar方法里这种逻辑,如果直接放在生成器内部的话,那就失去了一开始使用生成器的理由,应该有意把这样的细节从生成器中抽象出来,以避免它把高层次的任务表达变得杂乱。


Charon
57 声望16 粉丝

世界核平