Skip to content
大纲

asyncawait ​

定义 ​

async/await 是 es7 正式加入,用于处理异步操作 generator + Promise 的语法糖。

解决啥问题 ​

  1. 回调地狱(Callback Hell): 在 JavaScript 的异步编程中,经常需要使用回调函数来处理异步操作的结果。然而,当多个异步操作需要按顺序执行时,回调函数很容易形成嵌套,导致代码结构混乱,难以阅读和维护。这种现象被称为“回调地狱”。async/await 允许我们使用同步的写法来编写异步代码,避免了嵌套回调,使代码更加清晰和易于理解。
  2. 更好的错误处理: 在回调函数中处理错误通常比较繁琐,因为需要在每个回调函数中显式地检查错误。使用 async/await 时,可以使用 try/catch 语句来捕获和处理异步操作中抛出的错误。这使得错误处理更加集中和一致,易于维护。
  3. 代码的可读性和可维护性: async/await 语法使得异步代码看起来更加直观和易于理解。它允许我们以同步的方式编写异步代码,使得代码结构更加清晰,易于阅读和维护。同时,由于避免了嵌套回调,代码也更容易进行重构和扩展。
  4. 更自然的控制流: 使用 async/await,我们可以像处理同步代码一样处理异步代码,包括使用条件语句、循环等控制流语句。这使得异步代码的控制流更加自然和直观,易于理解和编写。
  5. 支持 Promise 链的简化: async/await 是基于 Promise 实现的,但它提供了更加简洁和易用的语法。通过 await 关键字,我们可以直接等待一个 Promise 的解析结果,而无需使用.then()和.catch()链式调用。这使得代码更加简洁和易于阅读。
  6. 更好的调试体验: 由于 async/await 使异步代码看起来像同步代码一样,因此调试起来也更加方便。开发者可以使用调试工具逐步执行代码,查看变量的值以及调用栈等信息,从而更容易地定位和解决问题。

总之,async/await 为 JavaScript 的异步编程带来了许多好处,使得代码更加清晰、易于阅读和维护,同时提供了更好的错误处理和调试体验。

注意点 ​

  1. await 只能在 async 中使用
  2. async 返回的是一个 Promise
  3. await 不能处理状态为 rejected 的 Promise,需要 Promise 处理 rejected 后返回,或者使用 try catch 包裹 await 执行

实现原理 ​

  1. 调用 async,js 会将函数转换为一个 Promise 函数,返回出去
  2. 同时会生成一个生成器函数,将 await 的表达式转换为 yield 表达式
  3. Promise 函数内部会去自动去调用生成器函数的 next 方法
  4. 然后根据 done 判断算法执行结束,返回解决值
js
/* 自动执行next */
function co(gen) {
  return new Promise((res, rej) => {
    let next = (params) => {
      try {
        /* 获取yield右边表达式 */
        var { value, done } = gen.next(params);
      } catch (e) {
        return rej(e);
      }
      /* 根据done判断是否结束 */
      if (done) {
        res(value);
      } else {
        /* 用promise包裹,兼容value的值为promise */
        Promise.resolve(value).then((data) => {
          --data;
          /* 递归执行,实现自动 */
          next(data);
        });
      }
    };
    /* 开启执行 */
    next();
  });
}

function promiseCreater(params) {
  return new Promise((res, rej) => {
    setTimeout(() => {
      res(params);
    }, 1000);
  });
}

function* gen(params) {
  let data1 = yield promiseCreater(params);
  console.log(data1);
  let data2 = yield promiseCreater(data1);
  console.log(data2);
  let data3 = yield promiseCreater(data2);
  console.log(data3);
  return data3;
}

co(gen(100));

Released under the MIT License.