实现一个简单的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;
}
相关推荐
元气少女小圆丶6 分钟前
unity发布web嵌入到前端页面的接受参数
前端·unity·webgl
工业HMI实战笔记7 分钟前
【拯救HMI】:低碳制造:自动化技术如何助力企业节能降耗
运维·前端·自动化·交互·制造
柒和远方1 小时前
V043:BFF 层流式输出:从前端直连到生产级流式网关的架构演进
javascript·架构·node.js
用户938515635071 小时前
SSE 流式输出的工程化拐点——为什么你需要一个 BFF 层
javascript·人工智能·全栈
不简说2 小时前
JS 代码技巧 vol.4 — 10 个异步并发控制,Promise.all 这帮兄弟的踩坑实录
前端·javascript·面试
Sinclair2 小时前
安企CMS的安装-PHPStudy(小皮面板)部署
前端·后端
会飞的特洛伊2 小时前
IAM身份认证
前端·后端
钛态3 小时前
AI 组件生成评测:别只看页面能不能渲染
前端·vue·react·web
Hyyy3 小时前
requestAnimationFrame和setTimeout有什么不同
前端
Jackson__4 小时前
问到你想清楚,这个 skill 专治没想明白就写代码!
前端·github·ai编程