async/await 原理解析

理解 async/await 基于 Generator 和自动执行器的实现机制

问题

async/await 是如何实现的?它与 Generator 有什么关系?

解答

async/await 本质上是 Generator 函数的语法糖,配合自动执行器实现异步代码的同步写法。

Generator 基础

function* gen() {
  const a = yield Promise.resolve(1);
  const b = yield Promise.resolve(2);
  return a + b;
}

const g = gen();
console.log(g.next());  // { value: Promise{1}, done: false }
console.log(g.next(1)); // { value: Promise{2}, done: false }
console.log(g.next(2)); // { value: 3, done: true }

Generator 可以暂停执行,但需要手动调用 next() 并传入上一次的结果。

自动执行器

function co(generatorFn) {
  return function (...args) {
    // 获取迭代器
    const gen = generatorFn.apply(this, args);

    return new Promise((resolve, reject) => {
      function step(key, arg) {
        let result;
        try {
          result = gen[key](arg);
        } catch (error) {
          return reject(error);
        }

        const { value, done } = result;

        if (done) {
          // 迭代完成,返回最终值
          resolve(value);
        } else {
          // 继续迭代,等待 Promise 完成后递归调用
          Promise.resolve(value).then(
            (val) => step('next', val),
            (err) => step('throw', err)
          );
        }
      }

      // 启动迭代
      step('next');
    });
  };
}

使用示例

// 模拟异步请求
function fetchData(id) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(`data-${id}`), 100);
  });
}

// 使用 Generator + co
const getData = co(function* () {
  const a = yield fetchData(1);
  const b = yield fetchData(2);
  return [a, b];
});

getData().then(console.log); // ['data-1', 'data-2']

// 等价的 async/await 写法
async function getDataAsync() {
  const a = await fetchData(1);
  const b = await fetchData(2);
  return [a, b];
}

getDataAsync().then(console.log); // ['data-1', 'data-2']

错误处理

const withError = co(function* () {
  try {
    const a = yield Promise.reject(new Error('failed'));
  } catch (e) {
    console.log('caught:', e.message);
    return 'fallback';
  }
});

withError().then(console.log); // caught: failed → fallback

对比转换

async/awaitGenerator + co
async functionco(function*)
await promiseyield promise
return valuereturn value
try/catchtry/catch

关键点

  • async 函数返回 Promise,await 暂停执行等待 Promise 完成
  • Generator 的 yield 可以暂停函数,next() 恢复执行并传值
  • 自动执行器递归调用 next(),将 Promise 结果传回 Generator
  • await 后的值会被 Promise.resolve() 包装,非 Promise 也能用
  • 错误通过 gen.throw() 抛入 Generator,可被 try/catch 捕获