关于前端:2K字就能理解的asyncawait原理还要拖多久

42次阅读

共计 4915 个字符,预计需要花费 13 分钟才能阅读完成。

前言

上篇文章 5K 字 由浅入深聊聊 Promise 实现原理,中讲述了 Promise 外部的实现原理。明天来聊聊 asyncawait,那么 async 与 await 到底是什么呢。都说是 语法糖,就来深刻了解下 async/await 吧

来看下 MDN 的概念

async 函数是应用 async 关键字申明的函数。async 函数是 AsyncFunction 构造函数的实例,并且其中容许应用 await 关键字

await 操作符用于期待一个 Promise 兑现并获取它兑现之后的值。它只能在异步函数或者模块顶层中应用。

asyncawait 关键字让咱们能够用一种更简洁的形式写出基于 Promise 的异步行为,而无需刻意地链式调用 promise

async

async在字面上的意思呢,是 异步 的概念,依据 MDN 的概念呢,阐明 async 申明的是一个异步构造函数,来看如下示例

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

根据上述示例内容,表述 async 申明了一个异步构造函数,并且调用了该函数,返回后果是一个 Promise 对象。

那问题来了,在看上述代码异步函数中 return 的是 1,后果却是一个 Promise 对象,不急,答案来了。

如果在函数中 return 的不是一个 promise, 那么将等同于应用 Promise.resolve(x)给包装起来

function fn() {return Promise.resolve(1);
}

将惯例函数转换成 Promise,返回值也是一个 Promise 对象

那这么看 async 与 Promise 有什么区别呢,看着是没什么区别,先不焦急,再接着看下await

await

await字面意思呢期待等待的意思,那到底是在等什么呢,等 promise 对象吗?

const fn1 = function fn() {return Promise.resolve(1);
};
async function result() {const r1 = await fn1();
  console.log(r1); // 1
}
result();

还能够等其它值吗?

const fn1 = function fn() {return Promise.resolve(1);
};
const fn2 = function test() {return "test";};
async function result() {const r1 = await fn1();
  const r2 = await fn2();
  console.log(r1, r2); // 1 'test'
}
result();

后果呢,不是 promise 对象的值也等到了。

await 不仅仅用于等 Promise 对象,它能够等任意表达式的后果。并且返回处理结果

只能在 async 函数外部应用

async/await 作用

根据上述内容呢,理解到 async 与 await 如何应用以及返回后果,那它们的作用体现到哪了呢?

先看下列有一个业务,业务内容呢须要反复申请操作,然而接口参数呢都须要在上一个申请后果中获取,先看下例子

function getFetch(type) {setTimeout(() => {
    let result = type + 1;
    return result;
  }, 1000);
}
getFetch(a).then((b) => {getFetch(b).then((c) => {getFetch(c).then((data) => {return data;});
  });
});

多重的异步操这是不是传说中的回调天堂呢,那怎么解决呢

用 promise 办法来解决

function getFetch(type) {return new Promise((resolve, reject) => {
    let result = type + 1;
    resolve(result);
  });
}

getFetch(0)
  .then((res) => {console.log(res);
    return getFetch(res);
  })
  .then((res) => {console.log(res);
    return getFetch(res);
  })
  .then((res) => {console.log(res);
  });

来用 async/await 来解决

function getFetch(type) {
  let result = type + 1;
  return result;
}

async function getResult(a) {const n1 = await getFetch(a);
  const n2 = await getFetch(n1);
  const n3 = await getFetch(n2);
  console.log(n1, n2, n3);
}
getResult(0);

输入后果呢与 Promise 解决方案是统一的,然而代码看起来简洁明了

用同步形式,执行异步操作 达到排队成果,解决回调天堂

Generator

async/await 为什么说是语法糖呢,是谁的语法糖呢?

在阮一峰的 ES6 入门教程中有说到:

async 函数是什么?一句话,它就是 Generator 函数的语法糖。

Generator 函数就是一个封装的异步工作,或者说是异步工作的容器。

异步操作须要暂停的中央,都用 yield 语句注明

调用 Generator 函数,返回的是指针对象(这是它和一般函数的不同之处),。调用指针对象的 next 办法,会挪动外部指针。

next 办法的作用是分阶段执行 Generator 函数。每次调用 next 办法,会返回一个对象,示意以后阶段的信息(value 属性和 done 属性)。value 属性是 yield 语句前面表达式的值,示意以后阶段的值;done 属性是一个布尔值,示意 Generator 函数是否执行结束,即是否还有下一个阶段。

理解 generator 用法

function* Generator() {
  yield "1";
  yield Promise.resolve(2);
  return "3";
}
var gen = Generator();
console.log(gen); // 返回一个指针对象 Generator {<suspended>}

调用 next 办法

let res1 = gen.next();
console.log(res1); // 返回以后阶段的值 {value: '1', done: false}

let res2 = gen.next();
console.log(res2); // 返回以后阶段的值 {value: Promise { 2}, done: false }

res2.value.then((res) => {console.log(res); // 2
});

let res3 = gen.next();
console.log(res3); // {value: '3', done: true}

let res4 = gen.next();
console.log(res4); // {value: undefined, done: true}

实现 async/await

async/await 的了解

  • async 函数执行后果返回的是一个 Promise
  • async 函数就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成 await
  • async/await 就是 Generator 的语法糖,其外围逻辑是迭代执行 next 函数

先来初步实现一个执行后果返回 Promise 的函数

function muYouAsync(){
      // 返回一个函数
    return function(){
          // 返回一个 promise
        return new Promise((resolve, reject) => {})
    }
}

并且呢 muYouAsync 承受一个 Generator 函数作为参数的,那咱们再来欠缺一下

function* gen() {}
// 承受一个 Generator 函数作为参数
function muYouAsync(gen){
      // 返回一个函数
    return function(){
          // 返回一个 promise
        return new Promise((resolve, reject) => {})
    }
}

咱们来测试下看下执行后果是否返回 Promise

const asyncGen = muYouAsync(gen)
console.log(asyncGen()) //Promise {<pending>}

看输入后果的话与执行后果返回 Promise 是统一的

至此呢第一局部函数执行返回后果已实现,那咱们来欠缺一下 Generator 函数

const getFetch = (nums) =>
  new Promise((resolve) => {setTimeout(() => {resolve(nums + 1);
    }, 1000);
  });

function* gen() {let res1 = yield getFetch(1);
  let res2 = yield getFetch(res1);
  let res3 = yield getFetch(res2);
  return res3;
}

Generator 函数也编写实现了,在下一步咱们要想,怎么让它执行起来了呢,那就须要用到 Generator 外围逻辑迭代执行 next 函数,留神点是须要将 next 迭代执行

// 承受一个 Generator 函数作为参数
function muYouAsync(gen) {
  // 返回一个函数
  return function () {
    // 返回一个 promise
    return new Promise((resolve, reject) => {
      // 执行 Generator 函数
      let g = gen();
      const next = (context) => {const { done, value} = g.next(context);
        if (done) {
          // 这时候阐明曾经是实现了,须要返回后果
          resolve(value);
        } else {
          // 继续执行 next 函数, 传入执行后果
          return Promise.resolve(value).then(val => next(val))
        }
      };
      next();});
  };
}

整体的逻辑曾经全都补充好了,那咱们还须要在欠缺下最初一步,async 返回的是 promise,所以咱们能够用 try catch 来捕捉

残缺代码

// 承受一个 Generator 函数作为参数
function muYouAsync(gen) {
  // 返回一个函数
  return function () {
    // 返回一个 promise
    return new Promise((resolve, reject) => {
      // 执行 Generator 函数
      let g = gen();
      const next = (context) => {
        let res
        try {res = g.next(context);
        } catch (error) {reject(error)
        }
        if (res.done) {
          // 这时候阐明曾经是实现了,须要返回后果
          resolve(res.value);
        } else {
          // 继续执行 next 函数, 传入执行后果
          return Promise.resolve(res.value).then(val => next(val), err => next(err))
        }
      };
      next();});
  };
}

那咱们最初来测试一下

const getFetch = (nums) =>
  new Promise((resolve) => {setTimeout(() => {resolve(nums + 1);
    }, 1000);
  });

function* gen() {let res1 = yield getFetch(1);
  let res2 = yield getFetch(res1);
  let res3 = yield getFetch(res2);
  return res3;
}

const asyncGen = muYouAsync(gen);
asyncGen().then(res => {console.log(res)}); // 4

结语

往年想法呢,是输入一些文章,总不能干了几年活了,还是碌碌无为,躺平过日子。年前那几天也刷了不少文章,看到了很多平台的前端打工人,都很卷的样子,那我往年也就卷一下子吧,腰断了就不卷了。
如果感觉此文略微有些帮忙的话,请不吝点个赞🥺🥺🥺

欢送大家到小家庭摸鱼交流学习,争当卷王沸点

正文完
 0