async和await
async
:声明一个异步函数(async function someName(){...}
)
- 自动将常规函数转换成
Promise
,返回值也是一个Promise
对象; - 只有
async
函数内部的异步操作执行完,才会执行then
方法指定的回调函数; - 异步函数内部可以使用
await
。
await
:暂停异步的功能执行(var result = await someAsyncCall()
)
- 放置在
Promise
调用之前,await
强制其他代码等待,直到Promise
完成并返回结果; - 只能与
Promise
一起使用,不适用与回调一起使用; - 只能在
async
函数内部使用。
await 容错
-
await
的后面需要是一个Promise
对象,如果不是则会被转成Promise
对象; - 只要其中一个如果
Promise
对象变为reject
状态,那么整个async
函数都会中断操作; - 如果状态是
resolve
,那么返回值则会变成then
里面的参数。
async function f() {
return await 123
}
f().then(v => {
console.log(v) // 123
})
怎样容错呢?由于await
后面的promise
运行结果可能是rejected
,最好把await
放入try {} catch {}
中。
await
后的异步操作,如果彼此没有依赖关系最好同时触发,在下面场景一会有介绍。
await
只能在async
函数之中,如果在普通函数中,会报错。
async、await 优缺点
-
async
和await
相比直接使用Promise
来说,优势在于处理then
的调用链,能够更清晰准确的写出代码; - 缺点在于滥用
await
可能会导致性能问题,因为await
会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。
var a = 0
var b = async () => {
a = a + await 10
console.log('2', a) // -> '2' 10
a = (await 10) + a
console.log('3', a) // -> '3' 20
}
b()
a++
console.log('1', a) // -> '1' 1
- 首先函数
b
先执行,在执行到await 10
之前变量a
还是0
,因为在await
内部实现了generators
,generators
会保留堆栈中东西,所以这时候a = 0
被保存了下来; - 因为
await
是异步操作,遇到await
就会立即返回一个pending
状态的Promise
对象,暂时返回执行代码的控制权,使得函数外的代码得以继续执行,所以会先执行console.log('1', a)
; - 这时候同步代码执行完毕,开始执行异步代码,将保存下来的值拿出来使用,这时候
a = 10
; - 然后后面就是常规执行代码了。
场景一
写一个函数,让它返回promise
对象,该函数的作用是2s
之后让数值乘以2
。
// 2s 之后返回双倍的值
function doubleAfter2seconds(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2 * num)
}, 2000)
} )
}
现在再写一个async
函数,从而可以使用await
关键字,await
后面放置的就是返回promise
对象的一个表达式,所以它后面可以写上 doubleAfter2seconds
函数的调用。
async function testResult() {
let result = await doubleAfter2seconds(30)
console.log(result)
}
testResult() // 打开控制台,2s 之后,输出了60.
具体到 我们的代码, 遇到await
之后,代码就暂停执行了, 等待doubleAfter2seconds(30)
执行完毕,doubleAfter2seconds(30)
返回的promise
开始执行,2 秒之后,promise
执行resolve
了, 并返回了值为60
, 这时await
才拿到返回值60
, 然后赋值给result
, 暂停结束,代码才开始继续执行,执行console.log
语句。
场景二
我们同时发出三个不互相依赖的请求,如果用async
/await
就显得不明智了。
async function getABC() {
let a = await getA() {}
let b = await getB() {}
let c = await getC() {}
return A*B*C
}
上面我们 A 需要 2s,B 需要 4s,C 需要 3s,我们如上图所示发请求,就存在彼此依赖的关系,c 等 b 执行完,b 等 a 执行完,从开始到结束需要(2+3+4)= 9s。
此时我们需要用Promise.all()
将异步调用并行执行,而不是一个接一个执行,如下所示:
async function getABC() {
let results = await Promise.all([ getValueA, getValueB, getValueC])
return results.reduce((total, value) => total * value)
}
这样将会节省我们不少的时间,从原来的的 9s 缩减到 4s,是不是很开心,耶~
网友评论