【悄咪咪学Node.js】5. 语法糖 async/await

async/await

1. 前言

本节课将会引导大家学习了解:

  • async/await 是什么
  • async/await 为什么会出现
  • 怎么正确使用 async/await

学习完本节课程后,应该具有:

  • 使用 async/await 改造 Promise 控制执行流程的能力
  • 从零开始编写使用 async/await 的异步函数的能力
  • 判断 await 运算符该不该使用的能力

2. async/await 是什么

2.1 笔者解释

async/await 是在 Node.js 7.6 版本及以上支持的 JavaScript ES7 特性。

async/await 是 Promise 的语法糖,其本质上就是 Promise。

async/await 是 异步扁平化 的最终手段,可以让你轻松写出同步风格的代码同时又拥有异步机制,更加简洁,逻辑更加清晰。

2.2 结构预览

先给一个直观的 async/await 例子,我们来看一下它的结构

js 复制代码
// 定义一个异步方法,返回一个 promise,1 秒后将 promise 状态修改为 已完成。
function promiseFn() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log('promise await');
            resolve();
        }, 1000);
    })
}

// 用 async 标识标记该方法为异步方法
async function asyncFn() {
    console.log('before promise await');
    // 用 await 标识,强调等待后面的 promise 执行完成。
    await promiseFn();
    console.log('after promise await');
}

下面分别介绍一下 async、await 的具体意思和使用方法。

2.3 async function 声明异步函数

在定义函数时,使用 async 标识符,可以将方法定义为异步函数。

那么异步函数究竟是什么东西呢?我们打印看一下。

js 复制代码
async function asyncFn() {
    return 'none JS';
}

console.log(asyncFn());

结果

shell 复制代码
Promise {<resolved>: "none JS"}

Tips:使用 async 标识符定义的异步函数,就是在该函数外包裹一层 Promise,并将该函数的返回值当作 Promise 已完成 状态的返回值。

2.4 await 等待运算符

await 是一个运算符,其功能是等待 任意表达式Promise 结果。

await 运算符必须使用在 异步函数 内部。

如果使用 await 标识一个普通表达式,效果不会有什么变化。

看一下 结构预览 中的例子的执行结果:

shell 复制代码
before promise await
promise await
after promise await

如果将 结构预览 中的例子中第十五行的 await 运算符去掉,执行结果却是:

shell 复制代码
before promise await
after promise await
promise await

由此可见,通过添加 await 运算符的确能有效等待 Promise 执行完成。

2.5 结论

async/await 没有增加新的机制,而是通过 Promise 实现。

async 能标识函数成为 异步函数,其实际就是在该函数外包裹一层 Promise,并将函数的返回值作为 Promise 已完成状态的返回值。

同理,在 异步函数 中抛出的异常,也会将 Promise 修改为已拒绝状态,并把异常作为已拒绝状态的返回值。

await 是一个运算符,其对普通表达式无显式影响,却能等待 Promise 对象完成。

3. async/await 解决了什么问题

3.1 异步扁平化

async/await 能将异步逻辑写成同步逻辑的代码风格,我们对比一下 async/await 和 Promise 的编写效果。

Promise

js 复制代码
task1()
    .then(task2)
    .then(task3)
    .then(task4)
    .then(task5);

async/await

js 复制代码
await task1();
await task2();
await task3();
await task4();
await task5();

在这个简单的对比中,async/await 写法明显缩进更少、相比于 Promise 的链式回调,也更容易让人理解。

4. 怎么用 async/await 优化 Promise 编码

读到这里,可能很多人觉得"如何使用async/await优化 Promise 编码"这个命题十分简单,认为去掉.then(),用 await 等待 Proimse 执行,再变量接住返回值就好了。比如:

js 复制代码
function wait(ms) {
    return new Promise(function(resolve, reject) {
        setTimeout(resolve, ms, true);
    });
}

Promise

js 复制代码
let wait1 = wait(1000),
    wait2 = wait(2000);
    
Promise.all([wait1, wait2])
    .then(function() {
        console.log('complete');
    })

使用 async/await 改造后,绝对不是:

js 复制代码
await wait(1000);
await wait(2000);

console.log('complete');

而应该是:

js 复制代码
let wait1 = wait(1000),
    wait2 = wait(2000);
    
await Promise.all([wait1, wait2]);
console.log('complete');

使用 async/await 对 Promise 编码进行 不当优化 的结果:

  • 轻则由于完全不允许异步,使得 Node.js 失去处理高并发的优势
  • 重则由于更改了原有流程控制,使得程序执行异常

Tips: 使用 async/await 改造 Promise 的一个重点是:理解清楚本来的代码流程,将可异步的保持异步,有上下文依赖关系的坚决保持同步。

4.1 代码例子

下面列举几种情况,供大家思考:

Promise

js 复制代码
let wait1 = wait(1000),
    wait2 = wait(2000);
    
Promise.all([wait1, wait2])
    .then(function() {
        console.log('complete');
    })

async/await

js 复制代码
let wait1 = wait(1000),
    wait2 = wait(2000);
    
await Promise.all([wait1, wait2]);
console.log('complete');

Promise

js 复制代码
let wait1 = wait(1000),
    wait2 = wait(2000);
    
wait1
    .then(wait2)
    .then(function() {
        console.log('complete');
    })

async/await

js 复制代码
await wait(1000);
await wait(2000);

console.log('complete');

5. 小结

本节课程我们主要学习了 async/await 是什么async/await 解决了什么问题async/await 怎么使用

重点如下:

  1. 重点1

    async/await 是一颗语法糖,通过 Promise 实现。其最终目标是 异步扁平化

  2. 重点2

    async 能标识一个函数为 异步函数,即在该函数外部包裹一层 Promise。

    await 是一个运算符,它能等待一个表达式 或 Promise 的结果。

    await 运算符必须要在 异步函数 中使用。

  3. 重点3

    使用 async/await 来优化已存在的 Promise 代码时,必须要先理清原本的流程控制,将可异步的保持异步,有上下文依赖关系的坚决保持同步。否则将迎来 负优化

相关推荐
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈3 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水4 小时前
简洁之道 - React Hook Form
前端
正小安6 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch8 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光8 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   8 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   8 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web8 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery