ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

算法思维体操:基于generator生成器自己实现Async/Await(TypeScript)

算法思维体操:基于generator生成器自己实现Async/Await(TypeScript)

>>> ORIGIN全文地址:算法思维体操:基于generator生成器自己实现Async/Await(TypeScript)

推荐:编程鼠标·电竞鼠标

实现Async/Await

要挑战的任务是使用JavaScript的generator生成器来实现Async/Await。

问题描述

下面是一个Async/Await函数的示例。

asyncfunctiondoSomething(value){constresult1=awaitfetchFromNetwork(value+'-1');constresult2=awaitfetchFromNetwork(value+'-2');try{constresult3=awaitfailedFetchFromNetwork();}catch(error){console.error('Error fetching from network');}returnresult1+' '+result2;}doSomething('http://google.com').then(r=>console.log(`Got result:${r}`)).catch(console.error)

我们需要使用generator生成器和一个特别的封装函数“asynk”来实现同样功能。等效的示例为:

constdoSomething=asynk(function*(value){constresult1=yieldfetchFromNetwork(value+'-1');constresult2=yieldfetchFromNetwork(value+'-2');try{constresult3=yieldfailedFetchFromNetwork();}catch(error){console.error('Error fetching from network');}returnresult1+' '+result2;});doSomething('http://google.com').then(r=>console.log(`Got result:${r}`)).catch(console.error)

关于“asynk“的注意事项:

  1. 它接收一个generator生成器函数并返回一个新函数;
  2. 当返回的函数被调用时,它应该返回一个Promise期约。Promise期约应当对generator生成器函数的返回值有所处理;
  3. 返回函数的类型特征应该和传入generator生成器函数的类型特征匹配。唯一的例外是,如果generator生成器函数返回一个非Promise期约的类型,返回函数应该返回一个与那个类型相对应的Promise期约。
待处理事项
  • 如果愿意的话,你可以先实现无类型的方案。有些人觉得使用类型有所帮助,另外一些人则觉得后续添加类型更容易;
  • 先关注控制流,然后才是参数值返回值可能有所帮助。
规则
  • 你不能使用原生的Async/Await;
  • 请不要直接查阅与”如何使用generator生成器实现Async/Await“相关的网上资料。
参考文献

下面是一些你会觉得有用的链接。请悉听尊便访问这些链接,但务必仅限于此。

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next

下面的类型定义或许有所裨益:

interfaceGenerator<T=unknown,TReturn=any,TNext=unknown>extendsIterator<T,TReturn,TNext>{// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.next(...args:[]|[TNext]):IteratorResult<T,TReturn>;return(value:TReturn):IteratorResult<T,TReturn>;throw(e:any):IteratorResult<T,TReturn>;[Symbol.iterator]():Generator<T,TReturn,TNext>;}interfaceIteratorYieldResult<TYield>{done?:false;value:TYield;}interfaceIteratorReturnResult<TReturn>{done:true;value:TReturn;}typeIteratorResult<T,TReturn=any>=IteratorYieldResult<T>|IteratorReturnResult<TReturn>;
TypeScript代码模板:
// See README.md for instructions.// TODO: add type annotations.functionasynk(fn:any){// YOUR CODE HERE}// Playgroud for testing the code.console.clear();function*countUp(){for(leti=0;i<10;i++){yieldi;}}constg=countUp();console.log(g.next());console.log(g.next());// const playground = asynk(function* () {// const result = yield Promise.resolve('hello');// });// playground().catch(console.error)
最终实现:

无类型的JavaScript版本:

functionasynk(fn){// YOUR CODE HEREreturn(...args)=>newPromise((resolve,reject)=>{// Initialize the generator function, which might have signatures,// Extract the next() queue fisrt, then iterate another initialized generatorconstrunner=fn(...args);try{letpromiseCallbackQueue=[(res,slaveRunner)=>slaveRunner.next(res).value,];letresult=runner.next();// First round, collect promiseCallbackwhile(!result.done&&String(result.value)==='[object Promise]')
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进