达永编程网

程序员技术分享与交流平台

async/await原理以及手写async函数

在 JavaScript 中,async/await 是处理异步操作的语法糖,其底层基于 PromiseGenerator(生成器)。以下是它的核心原理和手写实现思路:

一、async/await的核心原理

  1. async 函数
  2. 返回一个 Promise,函数内部的值会被自动包装成 Promise。
  3. 若函数抛出错误,会返回 Promise.reject(error)。
  4. await 表达式
  5. 会暂停 async 函数的执行,等待一个 Promise 完成。
  6. 本质上是通过 Generator 的暂停/恢复机制 实现的,结合 Promise 的链式调用。

二、async/await与 Generator 的关系

原生 async/await 的实现可以简化为以下步骤:

  1. 将 async 函数转换为 Generator 函数(生成器)。
  2. 使用一个 自动执行器(如 co 库) 驱动 Generator 逐步执行,处理 yield 的 Promise。
  3. 通过递归调用 next() 方法,在 Promise 完成后恢复 Generator 的执行。

三、手写async函数实现

以下是一个简化版的 async 函数实现,模拟 async/await 的行为:

1. 手写asyncToGenerator函数

function asyncToGenerator(generatorFunc) {
  return function (...args) {
    const generator = generatorFunc.apply(this, args);

    return new Promise((resolve, reject) => {
      function step(key, arg) {
        let result;
        try {
          result = generator[key](arg); // 执行 next/throw
        } catch (error) {
          return reject(error); // 捕获同步错误
        }

        const { value, done } = result;
        if (done) {
          return resolve(value); // 生成器执行完毕
        } else {
          return Promise.resolve(value).then(
            val => step("next", val), // 递归处理下一个 yield
            err => step("throw", err) // 处理错误
          );
        }
      }

      step("next"); // 启动生成器
    });
  };
}

2. 使用示例

// 定义一个 Generator 函数(模拟 async 函数)
function* mockAsyncFunc() {
  try {
    const data1 = yield fetchData1(); // 模拟 await
    const data2 = yield fetchData2(data1);
    return data2;
  } catch (error) {
    console.error("Caught error:", error);
  }
}

// 转换为类似 async 的函数
const asyncFunc = asyncToGenerator(mockAsyncFunc);

// 调用
asyncFunc().then(result => {
  console.log("Final result:", result);
});

四、关键步骤解析

  1. 创建 Generator 对象
    通过 generatorFunc.apply(this, args) 创建生成器实例。
  2. 驱动执行(step 函数)
  3. step("next") 启动生成器,首次调用 generator.next()。
  4. 如果生成器 yield 一个 Promise,等待其完成后继续执行 step("next", val)。
  5. 如果 Promise 失败,调用 step("throw", err) 抛出错误。
  6. 错误处理
  7. 使用 try/catch 包裹生成器方法调用,捕获同步错误。
  8. 通过 Promise.resolve(value).then(...) 处理异步错误。

五、与原生async/await的区别

特性

原生 async/await

手写实现(Generator + 执行器)

语法

内置关键字,更简洁

需要手动编写 Generator 和执行器

错误处理

自动捕获同步/异步错误

需手动处理 try/catch 和 throw

性能

引擎优化,性能更高

递归调用可能有额外开销

返回值

始终返回 Promise

依赖执行器返回 Promise

兼容性

ES2017+

可在 ES6 环境中模拟

六、总结

  • 核心原理:async/await 本质是 Generator + 自动执行器 的语法糖,通过暂停/恢复函数执行管理异步流程。
  • 手写关键:将 Generator 的 yield 与 Promise 链式调用结合,递归驱动生成器执行。
  • 实际应用:理解这一机制有助于深入掌握异步编程,但生产环境应直接使用 async/await。

通过手写实现,可以更直观地理解 async/await 的底层逻辑,但原生语法在性能和可读性上更具优势。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言