实现一个简单的async await

async await实际上是yield语法糖,当然我们首先得知道async await是怎么转换成yield的,

例如:

typescript 复制代码
async function(){
  await Promise.reject(1);
  return await Promise.reject(1)
}

实际上转换成的是(以下是简化过的):

javascript 复制代码
function a() {
    return __awaiter(function* () {
        yield Promise.reject(1);
        return yield Promise.reject(1);
    });
}
a();

__awaiter实际上就是用yield实现的async await语法糖。简单来说,就是用yield写一个自动执行器,并且返回一个Promise对象,Promise对象的状态由执行过程的情况而定。

所以我们可以很简单的得出以下代码:

typescript 复制代码
function __awaiter(fun: GeneratorFunction) {
  let resolveFn: (value: unknown) => void;
  let rejectFn: (value: unknown) => void;
  const generator = fun(); // 执行转换后的generator
  const promise = new Promise((resolve, reject) => {
    resolveFn = resolve;
    rejectFn = reject;
  });
  return promise; // 返回的promise
}

然后我们简单实现一个自动执行器:

typescript 复制代码
function __awaiter(fun: GeneratorFunction) {
  let resolveFn: (value: unknown) => void;
  let rejectFn: (value: unknown) => void;
  const generator = fun();
  const promise = new Promise((resolve, reject) => {
    resolveFn = resolve;
    rejectFn = reject;
  });
  
  // 如果yield之后返回的是简单类型,则把它包装成Promise
  const adopt = (value: unknown) => {
    return value instanceof Promise ? value : Promise.resolve(value);
  };

 // 自动执行器
  const step = (preValue?: unknown) => {
      const { value, done } = generator.next(preValue);
      adopt(value).then(
        nextValue => {
           // empty
        },
        reason => {
           // empty
        },
      );
  };

  // 执行自动执行器
  step();
  return promise;
}

但是我们可以看到adopt后面的then函数还是空的,这里实际上就是要根据执行状态来改变Promise对象的状态。

执行过程中的情况大概分为三种:

1. 执行过程顺利,prmiosevalue取决于最后一次generator.next()的值。

所以很简单,我们可以得出如下代码:

typescript 复制代码
function __awaiter(fun: GeneratorFunction) {
  let resolveFn: (value: unknown) => void;
  let rejectFn: (value: unknown) => void;
  const generator = fun();
  const promise = new Promise((resolve, reject) => {
    resolveFn = resolve;
    rejectFn = reject;
  });
  
  // 如果yield之后返回的是简单类型,则把它包装成Promise
  const adopt = (value: unknown) => {
    return value instanceof Promise ? value : Promise.resolve(value);
  };

 // 自动执行器
  const step = (preValue?: unknown) => {
      const { value, done } = generator.next(preValue);
      adopt(value).then(
        nextValue => {
           // 执行一切顺利
           // 执行一切顺利
           // 执行一切顺利
           // 执行一切顺利
           // 执行一切顺利
           if (done) {
            resolveFn(nextValue);
          } else {
            step(nextValue);
          }
        },
        reason => {
           // empty
        },
      );
  };

  // 执行自动执行器
  step();
  return promise;
}

2 . 执行过程中出现问题,例如直接throw xxx,抛出错误,此时需要在next()外面包裹try{}catch{},并且将错误原因赋值给rejectFn函数,并中断自动执行器。

从一个yield另一个yield中间发生了错误,这时需要在执行器外层嵌套try{}catch{}

typescript 复制代码
function __awaiter(fun: GeneratorFunction) {
  let resolveFn: (value: unknown) => void;
  let rejectFn: (value: unknown) => void;
  const generator = fun();
  const promise = new Promise((resolve, reject) => {
    resolveFn = resolve;
    rejectFn = reject;
  });

  const adopt = (value: unknown) => {
    return value instanceof Promise ? value : Promise.resolve(value);
  };

  const step = (preValue?: unknown) => {
  // 外层嵌套try catch
  // 外层嵌套try catch
  // 外层嵌套try catch
  // 外层嵌套try catch
  // 外层嵌套try catch
  // 外层嵌套try cat
    try {
      const { value, done } = generator.next(preValue);

      adopt(value).then(
        nextValue => {
          if (done) {
            resolveFn(nextValue);
          } else {
            step(nextValue);
          }
        },
        reason => {
          // empty
        },
      );
    } catch (e) {
      rejectFn(e);
    }
  };

  step();
  return promise;
}

3. yield(await)后面的promise对象变为reject状态,并中断自动执行器

typescript 复制代码
function __awaiter(fun: GeneratorFunction) {
  let resolveFn: (value: unknown) => void;
  let rejectFn: (value: unknown) => void;
  const generator = fun();
  const promise = new Promise((resolve, reject) => {
    resolveFn = resolve;
    rejectFn = reject;
  });

  const adopt = (value: unknown) => {
    return value instanceof Promise ? value : Promise.resolve(value);
  };

  const step = (preValue?: unknown) => {
    try {
      const { value, done } = generator.next(preValue);

      adopt(value).then(
        nextValue => {
          if (done) {
            resolveFn(nextValue);
          } else {
            step(nextValue);
          }
        },
        reason => {
          // await 后面的promise变为了reject
          // await 后面的promise变为了reject
          // await 后面的promise变为了reject        
          if (done) {
            rejectFn(reason);
          } else {
            step(reason);
          }
        },
      );
    } catch (e) {
      rejectFn(e);
    }
  };

  step();
  return promise;
}

通过以上条件,得到最终代码:

typescript 复制代码
function __awaiter(fun: GeneratorFunction) {
  let resolveFn: (value: unknown) => void;
  let rejectFn: (value: unknown) => void;
  const generator = fun();
  const promise = new Promise((resolve, reject) => {
    resolveFn = resolve;
    rejectFn = reject;
  });

  const adopt = (value: unknown) => {
    return value instanceof Promise ? value : Promise.resolve(value);
  };

  const step = (preValue?: unknown) => {
    try {
      const { value, done } = generator.next(preValue);

      adopt(value).then(
        nextValue => {
          if (done) {
            resolveFn(nextValue);
          } else {
            step(nextValue);
          }
        },
        reason => {
          if (done) {
            rejectFn(reason);
          } else {
            step(reason);
          }
        },
      );
    } catch (e) {
      rejectFn(e);
    }
  };

  step();
  return promise;
}
相关推荐
李剑一13 小时前
Vue实现大屏获取当前所处城市及当地天气(纯免费)
前端
踢足球092913 小时前
寒假打卡:2026-2-7
java·开发语言·javascript
_果果然13 小时前
这 7 个免费 Lottie 动画网站,帮你省下一个设计师的工资
前端
QT.qtqtqtqtqt13 小时前
uni-app小程序前端开发笔记(更新中)
前端·笔记·小程序·uni-app
闻哥13 小时前
Kafka高吞吐量核心揭秘:四大技术架构深度解析
java·jvm·面试·kafka·rabbitmq·springboot
楚轩努力变强13 小时前
iOS 自动化环境配置指南 (Appium + WebDriverAgent)
javascript·学习·macos·ios·appium·自动化
Aliex_git13 小时前
跨域请求笔记
前端·网络·笔记·学习
2501_9011478313 小时前
面试必看:优势洗牌
笔记·学习·算法·面试·职场和发展
李日灐13 小时前
C++进阶必备:红黑树从 0 到 1: 手撕底层,带你搞懂平衡二叉树的平衡逻辑与黑高检验
开发语言·数据结构·c++·后端·面试·红黑树·自平衡二叉搜索树
John_ToDebug13 小时前
引擎深处的漫游者:构建浏览器JavaScript引擎的哲学与技艺
javascript·chrome·js