当前位置:首页 > 技术文章 > 正文内容

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

zonemu1个月前 (09-04)技术文章16

在 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 的底层逻辑,但原生语法在性能和可读性上更具优势。

相关文章

快速上手React(快速上手的高级表达)

web前端三大主流框架1、Angular大家眼里比较牛的框架,甚至有人说三大框架中只有它能称得上一个完整的框架,因为它包含的东西比较完善,包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等...

VIM配置整理(vim配置教程)

一、基本配色set number set showcmd set incsearch set expandtab set showcmd set history=400 set autoread se...

(一)熟练HTML5+CSS3,每天复习一遍

前言学习网页的概念和分类,了解静态网页和动态网页的不同;了解网页浏览器的工作原理。了解HTML,XHTML,HTML5的概念,制作简单的HTML页面的开发。什么是网页可以在internet上通过网页浏...

15款测试html5响应式的在线工具(测试类h5)

手机、平板灯手持设备的增多,网站要顺应变化,就必须要做响应式开发,响应式网站最大的特点在于可以在不同设备下呈现不同的布局,是基于html5+css3技术,目前越来越多的网站开始采用了响应式设计,而下面...

HTML5设计与制作哪家强?全省50多所高职院校齐聚中山比拼

3月22日下午,2018-2019年广东省职业院校学生专业技能大赛“HTML5交互融媒体内容设计与制作”赛项在中山火炬职业技术学院开幕。全省51所高职院校的52支参赛队伍参加此次大赛。参赛师生将于3月...

简析html5、html的13条区别(html5和html的突出优点)

html5的流行近一两年,在国内主要是移动端和html5游戏的发展,国外也是最近纷纷使用html5,如谷歌,全面的停止flash的广告的投放量,用html5取代之,那么html5较html的区别在哪里...