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函数:

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

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

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

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

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

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

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,就能捕获错误。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐