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

实现Async/Await

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

问题描述

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

async function doSomething(value) {
   
    const result1 = await fetchFromNetwork(value + '-1');
    const result2 = await fetchFromNetwork(value + '-2');
    try {
   
        const result3 = await failedFetchFromNetwork();
    } catch (error) {
   
        console.error('Error fetching from network');
    }
    return result1 + ' ' + result2;
}
doSomething('http://google.com')
    .then(r => console.log(`Got result: ${
     r}`))
    .catch(console.error)

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

const doSomething = asynk(function* (value) {
   
    const result1 = yield fetchFromNetwork(value + '-1');
    const result2 = yield fetchFromNetwork(value + '-2');
    try {
   
        const result3 = yield failedFetchFromNetwork();
    } catch (error) {
   
        console.error('Error fetching from network');
    }
    return result1 + ' ' + 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

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

interface Generator<T = unknown, TReturn = any, TNext = unknown> extends Iterator<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>;
}

interface IteratorYieldResult<TYield> {
   
    done?: false;
    value: TYield;
}

interface IteratorReturnResult<TReturn> {
   
    done: true;
    value: TReturn;
}

type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
TypeScript代码模板:
// See README.md for instructions.

// TODO: add type annotations.
function asynk(fn: any) {
   
  // YOUR CODE HERE
}

// Playgroud for testing the code.
console.clear();

function* countUp() {
   
    for (let i = 0; i < 10; i++) {
   
        yield i;
    }
}

const g = countUp();
console.log(g.next());
console.log(g.next());

// const playground = asynk(function* () {
   
//     const result = yield Promise.resolve('hello');
// });
// playground().catch(console.error)
最终实现:

无类型的JavaScript版本:

function asynk(fn) {
   
  // YOUR CODE HERE
  return (...args) =>
    new Promise((resolve, reject) => {
   
      // Initialize the generator function, which might have signatures,

      // Extract the next() queue fisrt, then iterate another initialized generator
      const runner = fn(...args);
      try {
   
        let promiseCallbackQueue = [
          (res, slaveRunner) => slaveRunner.next(res).value,
        ];
        let result = runner.next();

        // First round, collect promiseCallback
        while (!result.done && String(result.value) === '[object Promise]') {
   
          promiseCallbackQueue.push(
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值