async / await 是 ES2017(ES8) 提出的基于 Promise 解决异步的最终方案。上一篇文章介绍了 回调地狱 与 Promise(JavaScript),因为 Promise 的编程模型依然充斥着大量的 then 方法,其虽然解决了回调地狱的问题,但是在语义化及代码可读性方面依然存在缺陷,这就是 async / await 出现的原因。
async
(异步):用来声明一个异步函数;await
(async wait):用来等待异步函数执行- async 是一个加在函数前的修饰符,被 async 定义的函数会默认返回一个 Promise 对象 resolve 的值,因此对 async 函数可以直接使用 then 方法
// 默认返回 Promise 对象成功值
async function fun() {
console.log('用户数据读取中~~');
return '用户数据读取成功!!';
}
fun().then(val => {
console.log(val)
})
// 根据 Promise 对象决定返回值
async function fun() {
console.log('用户数据读取中~~')
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据读取成功!!')
}, 3000)
})
}
fun().then(value => {
console.log(value)
})
console.log(1);
console.log(2);
console.log(3);
若单有 async,则和 Promise 功能相似,但配合上 await 则效果完全不同
- await 也是一个修饰符,只能放在 async 定义的函数内
- await 修饰的若是 Promise 对象:可获取 Promise 中返回的内容( resolve 或 reject 的参数),并会阻塞该函数内后面的代码直到获取到返回值后语句才会往下执行;若不是 Promise 对象:将此非 Promise 的语句当做 await 表达式的结果
// 非 Promise 对象
async function fun() {
console.log('用户数据读取中~~');
let a = await '用户数据读取成功!!';
console.log(a);
}
fun()
async function fun() {
console.log('用户数据读取中~~')
console.log(1);
console.log(2);
console.log(3);
// Promise 对象
let a = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据读取成功!!')
}, 3000)
})
console.log(a);
}
fun()
async function fun() {
let a = await 768
console.log(a)
let b = await '用户数据读取中...'
console.log(b)
// 注意:此处等待对象为函数,故需通过()调用
let c = await function () {
return '预计时间:3s'
}()
console.log(c)
let d = await new Promise((resolve, reject) => {
setTimeout(function () {
resolve('用户数据读取成功!!')
}, 3000)
})
console.log(d)
}
fun()
由以上案例可知 await 不仅可以用于等 Promise 对象,还可以等任意表达式,即 await 后面实际是可以接普通函数调用或者直接量的。不过我们更多的是放一个返回 Promise 对象的表达式,它等待的是 Promise 对象执行完毕所返回的结果。
// 非 Promise 对象
function notPromise(time) {
setTimeout(() => {
console.log(time);
return 1;
}, time)
}
async function fun() {
// 将 notPromise 所执行语句当做 await 表达式的结果
let a = await notPromise(3000);
let b = notPromise(2000);
let c = await notPromise(1000);
console.log(a);
console.log('先执行我捏~')
}
fun();
// 定义一个异步函数,time秒后才能获取到值
function fun(time) {
// Promise 对象
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据读取成功!!')
}, time)
})
}
async function test() {
console.log(1);
console.log(2);
console.log(3);
// 获取到 Promise 对象所返回的结果( resolve参数 )
let a = await fun(3000);
console.log(a)
}
test()
上一篇文章 回调地狱 与 Promise(JavaScript)中通过 Promise
解决了回调地狱问题,但不断地调用 then
链使代码看起来十分冗余从而导致可读性变差,故本文通过 asysc 与 await
来简化上文代码。
问题回顾:分别间隔 3s、2s、1s 按顺序输出:
我在定时器1里捏!!
,我在定时器2里捏!!
,我在定时器3里捏!!
await 的优势在于简化处理 then 链,使 异步代码 的书写方式更接近于 同步代码
function promise(value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value)
}, time)
})
}
async function fun() {
let a = await promise('我在定时器1里捏!!', 3000)
console.log(a);
let b = await promise('我在定时器2里捏!!', 2000)
console.log(b);
let c = await promise('我在定时器3里捏!!', 1000)
console.log(c);
}
fun()
最后我们可以通过三张图片来直观对比一下三种写法:
1.回调地狱
2.Promise
3.async + await
注意
await 必须写在 async 函数中, 但 async 函数中可以没有 await
在使用 await 的时候我们只是暂停了函数,而非整段代码
async/await 与 Promise 并不存在谁代替谁的说法,因为 async/await 是寄生于 Promise、Generater 的语法糖。使用 async/await 可以实现用同步代码的风格来编写异步代码,而异步编程的最高境界就是不关心它是否是异步,async/await 很好的解决了这一点。