1-1.await
await的意思就是等待。它后面可以跟一個表達式。如果是值(如字符串、數字、普通對象等等)的話,返回值就是本身的值。- 不過最常用的是后面跟一個
promise對象。await會等待這個promise的狀態由pending轉為fulfilled或者rejected。在此期間它會阻塞,延遲執行await語句后面的語句。 - 如果
promise對象的結果是resolve,它會將resolve的值,作為await表達式的運算結果。
語法糖本質
其實await與async本身就是promise化編程的一種語法糖。對比一下兩種寫法。
// 異步promise化的函數--模擬請求后端接口
function asyncFn () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (true) {
console.log('resolve console')
resolve('resolve return')
} else {
reject('reject return')
}
}, 2000)
})
}
// promise
asyncFn().then((res) => {
console.log(res)
}, (err) => {
console.log(err)
})
// await
try {
var res = await asyncFn()
console.log(res)
} catch(err) {
console.log(err)
}
// 如果有第二次請求的話,promise需要在then方法繼續調用,再用then接受,過多的嵌套依然會增加閱讀難度。而await async只需要像寫同步代碼一樣繼續書寫就可以,它是解決異步編程回調地獄的終極手段。
例一
// ps:由於js本身現在已經限制了await必須用在async函數中,否則會報錯。所以請將下面的復制粘貼到瀏覽器控制台查看結果
function asyncFn () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (true) {
console.log('resolve console')
resolve('resolve return')
} else {
reject('reject return')
}
}, 2000)
})
}
var value1 = await asyncFn()
var value2 = await 'plain text'
console.log(value1)
console.log(value2)
//瀏覽器會依次打印 ‘resolve console’ ‘resolve return’ ‘plain text’
例二
如果你對結果有疑問,可以將asyncFn前面的await去掉,再在瀏覽器控制台執行一次。

這兩次對比一下,會發現第二次的resolve console是最后打印出來的,而第一次的是第一個打印的。
根本原因就是第一次代碼中await阻塞了后面語句的執行,等待promise確定結果后繼續執行后面語句。
例三
根據前兩例可想而知,如果兩個await的后面跟着的都是promise對象。那么第二個await等待的時間是它本身等待的時間加上第一個await等待的時間
function asyncFn1 () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (true) {
console.log('resolve console1')
resolve('resolve return1')
} else {
reject('reject return1')
}
}, 2000)
})
}
function asyncFn2 () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (true) {
console.log('resolve console2')
resolve('resolve return2')
} else {
reject('reject return2')
}
}, 2000)
})
}
var value1 = await asyncFn1()
var value2 = await asyncFn2()
// 復制並執行,會發現2s后打印了‘resolve console1’,4s后打印了‘resolve console2’
思考
// 已經知道了await會阻塞代碼的執行,如果我們在實際開發中有這樣的代碼。
function fn () {
// 假設request是請求后端接口
var value = await request()
console.log(value)
// ...
}
fn()
var arr = []
arr.push('1')
// ...其他不依賴后端接口邏輯
在fn調用后,由於await的阻塞,必然會影響到下面的邏輯。在實際開發中,如果后端接口5s才響應,那么下面的代碼就需要等待5s。顯然這是不合理的,為了解決這種現象,就需要async聲明。
1-2.async
之前我們知道了await會阻塞代碼的執行。而解決這個弊端的手段就是async聲明。
async function asyncFn () {
return 'async'
}
console.log(asyncFn())
控制台打印一下,會發現打印的是一個promise對象。而且是Promise.resolve對象。resolve的值就是asyncFn的函數返回值async。

如果函數沒有返回值的話,它自然返回的會是Promise.resolve(undefined)。
其實之所以async聲明能解決await的阻塞問題,就是因為async聲明將函數作了一層promise包裝,這樣內部的異步操作其實就是由pending轉為resolve或者reject的過程。這樣函數本身就能夠隨意調用,函數內部的await也不會再影響到函數外部的代碼執行。
