前言
本文主要内容:通过多个使用 async & await 的函数与使用 Promise 的函数之间的对比,进一步理解 async & await 作为 Promise 语法糖的功能与效果
什么是 async
在介绍什么是 async 前,让我们回顾一下上节课讲过的 Promise,如下
function fn1() {
return Promise.resolve(1);
}
fn1().then(r => {
console.log(r);
})
fn1函数返回了一个 Promise 对象,这个 Promise 对象里异步保存了一个数据 1,当我们要读取这个异步函数时,使用了 then 方法,从而获得了这个值 1
接下来让我们看看 async 是如何实现这段代码的
async function fn2() {
return 1;
}
fn2().then(r => {
console.log(r);
})
可以看到fn2函数前加了 async,返回值是 1,但是却能够调用 then 方法
所以我们通过console.log(fn2());可以获得如下结果
果然返回值不是一个普通的 1,而是 resolve(1) 的 Promise 对象
那么我们就能大致给出 async是什么 的回答
async 是 Promise 的一个语法糖,可以更快捷、更方便地创建一个异步函数,返回值会自动被封装到一个Promise 对象中
什么是 await
再来看一段用 Promise 实现的代码,如下
function sum(a, b) {
return new Promise(resolve => {
setTimeout(() => {
resolve(a+b)
},1000);
})
}
async function fn3() {
sum(3, 3).then(r => {
console.log(r)
})
}
可以看到 sum() 是一个异步函数,而 fn3() 调用了它,并且通过 then 方法获取了数据
现在用 await 来实现一下相同的结果
async function fn4() {
let result = await sum(3, 3);
console.log(result);
}
可以看到没有用 then 方法,反而仅仅用赋值运算符'='完成了result的赋值
也就是,Promise 解决了异步调用中回调函数问题,async 实现了以同步的方式调用异步的代码的功能
如果上面的还不太容易看出来,再看看下面这个链式调用
function fn3() {
sum(3, 3)
.then(r => sum(r, 4))
.then(r => sum(r, 5))
.then(r => {
console.log(r);
})
}
而使用 async & await 是这样的
function fn4() {
let result = await sum(3, 3);
result = await sum(result, 4);
result = await sum(result, 5);
console.log(result);
}
这样就很容易看出,我们用同步的方式调用了异步的函数
async & await 的作用范围
接下来让我们进一步了解 async & await
不加 await
来看这么个问题,以下代码的输出是
async function fn4() {
console.log(1);
console.log(2);
console.log(3);
}
fn4();
console.log(4);
是的,当我们不添加 await 时,程序正常的一行一行执行,它的等效 Promise 代码如下
function fn5() {
return new Promise(resolve => {
console.log(1);
console.log(2);
console.log(3);
resolve();
})
}
可以看到我们返回的 Promise 对象是没有异步存储值的,而只是打印了 1、2、3
加上 await
那么当我们加上 await 时,程序的输出又会变成什么样呢,如下
async function fn4() {
console.log(1);
await console.log(2);
console.log(3);
}
fn4();
console.log(4);
可以看到,3被异步打印了出来
这是因为使用await调用函数后,当前函数后边的所有代码会在当前函数执行完毕后,被放入微任务队列中。所以 await 使得
- 1 是正常被打印的
- 2 是当前任务打印的
- 3 被放入了微任务队列,在 4 之后打印
那么来看看使用 Promise 的写法如何
function fn5() {
return new Promise(resolve => {
console.log(1);
console.log(2);
resolve();
}).then(r => {
console.log(3);
})
}
也就是 3 被 then 方法放入微任务队列里异步执行了
小结
-
async 是 Promise 的语法糖,可以更快捷、方便地定义异步函数
-
当我们通过await去调用异步函数时,它会暂停代码的运行,直到异步代码执行有结果,才会将结果返回,然而这并不意味着程序会被阻塞,await 只能用于 async 声明的异步函数中,或 ES模块的顶级作用域中,从而避免阻塞其他程序代码的执行