手写async await

566 阅读3分钟

手写async await

async awaitgenerator函数的语法糖,主要用到了generator函数的yield来暂停,next来继续执行

async 写法

async function getData()
  const data1 = await getData1();
  console.log('data1:',data1);
  const data2 = await getData2();
  console.log('data2:',data2);
  return data2;
}

转化为 generator函数

const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000))

function* getDataG(){
  const data1 = yield getData()
  console.log('data:', data1);
  const data2 = yield getData()
  console.log('data2:', data2);
  return data2;
}

generator函数需要通过next来执行里面函数体,通过yield来暂停等待执行,这个函数不会自己执行,所以需要写一个函数调用next来帮助执行

asyncGenerator函数

这个函数的作用传进去一个generator函数,然后函数自动执行next

function asyncGenerator(generatorFunc) {
  // 返回一个new Promise
  return new Promise((resolve, reject) => {
    let gen = generatorFunc();
    // 然后定义一个setp() 接受一个参数nextF函数
    function setp(nextF) {
      // nextF 里面定义一个next变量
      let next;
      // try catch 执行nextF 成功的话next接收函数返回值 失败则return reject
      try {
        next = nextF();
      } catch (err) {
        return reject(err);
      }
      // 然后判断next的done的值 为true 直接return  resolve
      if (next.done) {
        return resolve(next.value);
      }
      // Promise.resolve(next.value) 这样可以不管next.value是不是promise 都可以使用then
      Promise.resolve(next.value).then(
        (res) => {
          // 继续执行 gen.next(next.value))递归下去
          setp(function () {
            return gen.next(res);
          });
        },
        (err) => {
          // 失败则使用gen.throw 方法
          setp(function () {
            return gen.throw(err);
          });
        }
      );
    }
    // 定义完然后执行setp()
    setp(function () {
      return gen.next();
    });
  });
}

函数执行解析

  1. 执行传进去的generatorFunc函数赋值为变量gen, 函数底部执行gen.next(),gen.next()函数,执行函数体中的代码,然后遇到yield暂停执行,yield的右边函数值赋值给变量nextnext的值{ value, done } 的结构,next.done false继续执行,使用Promiseresolve方法统一当异步数据处理,等待next.value异步then完成得到res并执行gen.next(res)

  2. 执行gen.next(res)res变量赋值给yield左边的变量,继续执行函数体中的代码,遇到yield暂停执行,yield的右边函数值赋值给变量nextnext.done false继续执行,使用Promiseresolve方法统一当异步数据处理,等待next.value异步then完成得到res并执行gen.next(res)

  3. next.donefalse的话就一直重复第二个步骤,递归下去,直到next.donnetrue就直接返回next.value,函数终止

ps:async使用异步代码也可以使用同步代码的方式编写,主要是因为函数体一遇到yield就需要等待yield右边方代码执行完毕才会继续执行。

函数步骤解析

  1. 第一次使用next()

    next()返回值赋值给变量next ,执行下方函数体中的代码,yield关键前的代码,执行yield右边的代码``getData();并使用then等待后将结果resnext.donefalse调用第二次next(res)这一步变量data1`并未赋值

    ps: 变量next保存留给下次调用next()的时候传入当参数

    console.log('start');
    getData();
    
  2. 第二次使用next()

    上一步中调用next(res)函数,执行下方函数体,res参数赋值给yield左边的变量,data1赋值成功,返回值赋值给变量next

    const data1 // data1 = res
    console.log('data:', data1);
    getData()
    

    next.donefalse,调用第三次next(res)

    直到遇到yield暂停执行,执行yield右边的代码getData();并使用then等待后将结果res,调用第三次next(res),这一步变量data2并未赋值

  3. 第三次使用next()

    上一步中调用next(res)函数,执行下方函数体,res参数赋值给yield左边的变量,data2赋值成功,返回值赋值给变量next

    const data2 = // data2 = res
    console.log('data2:', data2);
    return data2;
    

    next.donetrue,直接返回next.value,函数终止