async/await 原理

193 阅读3分钟

async/await

在日常开发中我们经常会使用到async/await,以下就是使用场景

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);

// 这里如果p2依赖于p1的成功结果,p3又依赖于p2的成功结果那么就会出现以下情况
// 这种情况下如果还参杂着一些业务逻辑 可读性很差

p1.then((data) => {
  p2.then((data2) => {
    p3.then((data3) => {
      console.log(">>>>>>回调地狱", data3);
    });
  });
});
// 或者
p1.then((data) => {
  return p2;
})
  .then((data) => {
    return p3;
  })
  .then((data) => {
    console.log(">>>>>>链式调用", data);
  });

// 使用async/ await
// 结果和promise是一个样的 但是看着更加简洁一些
async function result2() {
  const res1 = await p1;
  const res2 = await p2;
  const res3 = await p3;
  console.log(">>>>>> async/await", res1, res2, res3);
}
console.log(">>>>>>result2", 1,2,3);

async

字面意思就是异步 使用async的函数 返回值是一个Promise对象 async声明的是一个异步构造函数,来看如下示例

const fn1 = async function fn() {
  return 1;
};
console.log(">>>>>>>fn1", fn1());
// Promise {<fulfilled>: 1}

这里我们可以看到 使用async包裹的函数返回的是一个Promise对象,那么为什么会return 1会返回一个Promise呢,因为如果这里返回的 不是一个Promise那么这里就会用Promise.resolve(*) 包裹起来

await

字面意思就是等待, 不仅仅等待Promise对象,可以等任何表达式的结果 且只能在async内部使用

const fn2 = function test1() {
  return Promise.resolve(1);
};

const fn3 = function test2() {
  return "test";
};
async function result() {
  const res1 = await fn2();
  console.log('>>>>>停一下哥们')
  const res2 = await fn3();
  console.log(">>>>>>返回结果", res1, res2);
}
result(); //  console.log(">>>>>>返回结果", 1, test);

上面代码可以看到 用同步方式,执行异步操作达到排队效果,解决回调地狱 那么这个async/await 是怎么实现的呢下面我们就来说说Generator

Generator

Generator是封装的一个异步任务,或者说是一个异步任务的容器 需要暂停异步任务的地方,可以使用yield语句标明 调用Generator函数返回一个指针对象(这是与其他函数不同的地方), 调用指针对象的next方法,会移动内部指针。

function* gener() {
  yield 1;
  yield 2;
  yield Promise.resolve(3);
  return 3;
}
const gen = gener();
console.log("><>>>>>>", gen.next(), 1); // { value: 1, done: false }
console.log("><>>>>>>", gen.next(), 2); // { value: 2, done: false }
console.log("><>>>>>>", gen.next(), 3); // { value: Promise, done: false }
console.log("><>>>>>>", gen.next(), 4); // { value: 3, done: true }

在上面这段代码中可以看到,gener函数返回一个指针对象,调用指针的next 会返回当前阶段的对象 其中value 标识当前的值,done标识完成状态。

看完上面的Generator 函数我们回过头来看看 async/await 是怎么实现的呢,我们可以这样理解

  • 1.async 函数执行结果返回的是一个promise
  • 2.async 函数就是将Generator函数的星号(*)替换成async,将yield替换成await
  • 3.async/await 就是Generator的语法糖,其核心逻辑是迭代执行next函数

首先我们设定一个请求函数

function getFetch(num) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(num + 1);
    }, 1000);
  });
}

完善一下gener函数,这里说明一下,上面调用gen.next() 如果我们在next(*)传入参数 ,那么就是这个当前yield语句返回值

function* myGen() {
  const res1 = yield getFetch(1);
  const res2 = yield getFetch(res1);
  const res3 = yield getFetch(res2);
  return res3;
}

我们再设定一个 myAsync函数

// 接受一个Gennerator函数作为参数
function myAsync(gen) {
  // 返回一个函数
  return function () {
    // 返回一个promis
    return new Promise((resolve, reject) => {});
  };
}

完善一下 myAsync函数

function myAsync(gen) {
  return function () {
    return new Promise((resolve, reject) => {
      const g = gen();

      // 这里的 context 是传递给下一个
      const next = (context) => {
        let res;
        try {
          res = g.next(context);
        } catch (e) {
          reject(e);
        }

        const { value, done } = res;
        // 如果已经完成我们就直接返回成功
        if (done) {
          resolve(value);
        } else {
          // 没有完成的话 我们继续递归调用 直到done为true
          return Promise.resolve(value).then(
            (val) => next(val),
            (err) => next(err)
          );
        }
      };

      next();
    });
  };
}
const test = myAsync(myGen);

当然了 上面写的我自己都看的一脸懵逼我只是为了做一下笔记