实现一个简单的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;
}
相关推荐
hpoenixf9 分钟前
一天上线 + 零返工:我如何给复杂前端需求建立“安全感”
前端
逻辑驱动的ken36 分钟前
Java高频面试考点18
java·开发语言·数据库·算法·面试·职场和发展·哈希算法
广州华水科技1 小时前
单北斗GNSS变形监测系统在水利工程安全保障中的应用与优势分析
前端
yqcoder1 小时前
CSS 外边距重叠(Margin Collapsing):现象、原理与完美解决方案
前端·css
研究点啥好呢1 小时前
高德多模态算法工程师面试题精选:10道高频考题+答案解析
python·面试·llm·求职招聘·笔试·高德
fzil0012 小时前
自动投递简历 + 面试进度跟踪
人工智能·面试·职场和发展
其实防守也摸鱼2 小时前
面试常问问题总结--护网蓝队方向
网络·笔记·安全·面试·职场和发展·护网·初级蓝队
山楂树の2 小时前
图像标注大坑:img图片 + Canvas 叠加标注,同步放大后标注位置偏移、对不齐?详解修复方案及亚像素处理原理
前端·css·学习·canva可画
本山德彪2 小时前
我做了一个拼豆图纸生成器,把照片秒变图纸
前端
one_love_zfl2 小时前
java面试-微服务组件篇
java·微服务·面试