源码先锋

源码先锋

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

admin 107 66

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

一、async/await的核心原理

async函数

返回一个Promise,函数内部的值会被自动包装成Promise。

若函数抛出错误,会返回(error)。

await表达式

会暂停async函数的执行,等待一个Promise完成。

本质上是通过Generator的暂停/恢复机制实现的,结合Promise的链式调用。

二、async/await与Generator的关系

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

将async函数转换为Generator函数(生成器)。

使用一个自动执行器(如co库)驱动Generator逐步执行,处理yield的Promise。

通过递归调用next()方法,在Promise完成后恢复Generator的执行。

三、手写async函数实现

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

1.手写asyncToGenerator函数
functionasyncToGenerator(generatorFunc){returnfunction(args){constgenerator=(this,args);returnnewPromise((resolve,reject)={functionstep(key,arg){letresult;try{result=generator[key](arg);//执行next/throw}catch(error){returnreject(error);//捕获同步错误}const{value,done}=result;if(done){returnresolve(value);//生成器执行完毕}else{(value).then(val=step("next",val),//递归处理下一个yielderr=step("throw",err)//处理错误);}}step("next");//启动生成器});};}
2.使用示例
//定义一个Generator函数(模拟async函数)function*mockAsyncFunc(){try{constdata1=yieldfetchData1();//模拟awaitconstdata2=yieldfetchData2(data1);returndata2;}catch(error){("Caughterror:",error);}}//转换为类似async的函数constasyncFunc=asyncToGenerator(mockAsyncFunc);//调用asyncFunc().then(result={("Finalresult:",result);});
四、关键步骤解析

创建Generator对象
通过(this,args)创建生成器实例。

驱动执行(step函数)

step("next")启动生成器,首次调用()。

如果生成器yield一个Promise,等待其完成后继续执行step("next",val)。

如果Promise失败,调用step("throw",err)抛出错误。

错误处理

使用try/catch包裹生成器方法调用,捕获同步错误。

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