2025-08-24
JavaScript
00
请注意,本文编写于 110 天前,最后修改于 110 天前,其中某些信息可能已经过时。

async await 语法是ES7出现的,是基于ES6的 promise和generator实现的,那么js底层是如何实现的呢,让promise异步状态变为await的同步写法。

async/await 是建立在Promise之上的语法糖,它的底层实现原理是基于状态机的转换和生成器(Generator)函数。下面我将详细描述其工作原理。

  1. 生成器函数(Generator)和迭代器(Iterator) 生成器函数可以暂停和恢复执行。当调用生成器函数时,它返回一个迭代器对象,通过调用迭代器的next()方法可以逐步执行生成器函数体。每次遇到yield关键字,函数就会暂停执行并返回一个值。

  2. 将异步操作转化为同步写法 async/await 通过暂停和恢复执行来实现异步操作的同步写法。async函数本质上是一个生成器函数,但使用了async关键字标记。await后面的表达式会被包装成Promise。

  3. 状态机的实现 编译器(如Babel)会将async函数转换成生成器函数的形式,然后使用一个状态机(通常由一个包装函数实现)来管理生成器的状态,自动执行迭代过程。

转换步骤:

假设有这样一个async函数:

javascript
async function example() { const result = await someAsyncCall(); console.log(result); }

它会被转换成类似下面的生成器函数:

javascript
function example() { return spawn(function* () { const result = yield someAsyncCall(); console.log(result); }); }

这里的spawn函数就是一个自动执行器,它会管理生成器的状态,处理Promise的解析,并继续执行生成器直到结束。

  1. 自动执行器(spawn函数)的实现 自动执行器的作用是管理生成器的状态,处理每个yield出来的Promise,并根据Promise的结果(成功或失败)决定是继续执行还是抛出错误。

一个简化的自动执行器可能如下:

javascript
function spawn(generatorFunc) { return new Promise((resolve, reject) => { const generator = generatorFunc(); const step = (key, arg) => { let result; try { result = generator[key](arg); } catch (error) { return reject(error); } const { value, done } = result; if (done) { return resolve(value); } // 确保返回一个Promise Promise.resolve(value).then( value => step('next', value), error => step('throw', error) ); }; step('next'); }); }

步骤解析:

spawn函数返回一个Promise,这样调用者可以使用.then()和.catch()。

创建生成器对象generator。 定义一个step函数,用于控制生成器的执行。它根据状态('next'或'throw')调用生成器的相应方法(generator.next()或generator.throw())。

在首次调用时,使用step('next')启动生成器。

每次执行生成器的next或throw方法,都会返回一个对象{ value, done },其中value是yield后面的表达式的值(通常是一个Promise),done表示生成器是否已经结束。

如果生成器未结束(done为false),则等待Promise解析(使用Promise.resolve来确保它是一个Promise),然后根据解析结果:

  • 若成功,则使用step('next', value)将解析后的值传给生成器,并继续下一步。
  • 若失败,则使用step('throw', error)将错误抛出到生成器内部,可以被生成器内的try-catch捕获。

如果生成器结束(done为true),则解析外部的Promise(即整个async函数的Promise)为生成器函数返回的值(即return的值)。

  1. 错误处理

在async函数中,错误通过try-catch捕获。在自动执行器中,当生成器内部出现错误(包括异步操作reject)时,我们使用generator.throw()将错误抛入生成器,这样生成器内部如果有try-catch,就能捕获错误。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:繁星

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!