async函数

在ES2017中引入了async函数,使用该关键词可以说明该函数是一个异步函数,再配合await即可轻松实现异步执行的效果。

例如从指定的url地址上获取数据将数据返回,使用async如下

async function getData(url) {
    const data = await fetch(url)
    return data.text;
}

看起来实现方式和Generator很像,使用Generator方式

const co = require('co')
function* getData(url) {
    const data = yield fetch(url)
    return data.text
}
co(getData)

这里借助了co模块,这是一个Generator的运行器。可以看到,async的写法和Generator的写法很相似,其实async就是Generator的语法糖,只不过,Generator运行需要借助于运行器,async其实是使用的内置的运行器,这样会更加的方便。

运行器的实现思路就是将Generator包装在一个Promise函数中,不断迭代Generator的next,直到执行结束resolve,如果执行中出现错误直接reject出去,具体实现代码如下:

//该代码借鉴自阮一峰的《ECMAScript 6入门》
//http://es6.ruanyifeng.com/#docs/async#async-%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86
function spawn(genF) {
    return new Promise((resolve, reject) => {
        let gen = genF();

        function step(nextF) {
            let next;
            try {
                next = nextF()
            } catch (e) {
                //执行异常,reject这个Promise
                return reject(e)
            }

            //迭代结束时,resolve这个Promise
            if (next.done) {
                return resolve(next.value)
            }
            Promise.resolve(next.value).then(
                //递归next(),并将当前的value传递给下一个
                v => step(() => gen.next(v)),
                e => step(() => gen.throw(e))
            );
        }

        //初始迭代
        step(() => gen.next(undefined))
    })
}

调用方式如下

function testDelayFunc() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('hello world')
        }, 500)
    })
}

function* testGenerator() {
    const a = yield testDelayFunc()
    const b = yield 'good boy'
    console.log(a, b);
}

spawn(testGenerator); //hello world good boy
如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注