理解async..await的实现原理

async..await 作为 Promise 的语法糖,只能用一个字形容:甜!

还是先创建一个返回 Promise 的函数:

function asyncFun (arg) {
  if (arg) {
    return Promise.resolve('yes')
  } else {
    return Promise.reject('no')
  }
}

我们很想将一段异步代码以同步的方式书写,比如:

try {
  // 同步读取,避免回调
  const data = asyncFun(true);
  console.log(data);
} catch (err) {
  console.error(err);
}

但是,上面的代码并不会如期执行,因为 readFile 返回的实际上是一个 Promise 对象!

容器

但是假如有这样一个容器,它能如期的执行我们上面的这段代码,我们只需要把代码丢进这个特殊的容器里。

创建一个生成器容器:

// 运行生成器函数的一个容器
// 参数必须是一个生成器
function run(gen) {
    // 创建迭代器
    const task = gen();
    // 开始执行
    let result = task.next();
    (function step() {
        if (!result.done) {
            // 用Promise处理
            // 解释:无论result.value本身是不是promise对象,都会作为一个promise对象来异步处理
            const promise = Promise.resolve(result.value);
            promise.then(value => {
                // 把本次执行的结果返回
                // 也就是语句 const value = yield func(); 的返回值
                result = task.next(value);
                // 继续
                step();
            }).catch(err => {
                result = task.throw(err);
                // 继续
                step();
            })
        }
    }());
}

现在,我们有了这样的一个容器run,把那段“同步”代码丢进这个容器里:

run(function *() {
  try {
    const data = yield asyncFun(true)
    console.log(data);
  } catch (err) {
    console.error(err);
  }
});

完美,我们只是在刚才那段“同步”代码前加了一个 yield,即达到了效果!

转过头,我们再看看我们的async...await:

;(async () => {
  try {
    let ret = await asyncFun(true)
    console.log(ret)
  } catch (e) {
    console.log(e)
  }
})();

可以看出,只是将 *变成了async,yield 换成了 await,还省去了“容器”!

同步书写,异步执行

虽然我们是以同步的方式书写的代码,但从第一个 yield或await的位置开始,后续的代码其实都是异步执行的,举个例子:

;(async () => {
  try {
    console.log('开始执行');
    let ret = await asyncFun(true)
    console.log(ret)
  } catch (e) {
    console.log(e)
  }
})();
console.log('结束了!');

结果是:

开始执行
结束了!
true

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress