上一章我們說過了 Promise ,其實使用上已經足夠。就是在了解上,還需要自己多動手敲一些代碼;今天來說說另一個異步請求,是ES7中的新方法 async...await...
。
那麼我們知道了異步請求的優勢,也知道可以使用回調函數或者更好的方法Promise來處理異步,那麼為什麼還要有引入新的異步方法?
答案是Promise也有缺點:
首先Promise的代碼還達不到很簡潔的程度(如果有太複雜的異步,代碼也會很複雜,可讀性不高);
其次不能像同步代碼一樣友善擷取到錯誤資訊;
那麼async/await怎麼用,我們從字面意思了解:async:異步;await:等待
async 是異步的意思,是一個關鍵字,将 async 關鍵字放在函數前邊,表示某個函數就是一個異步函數,這樣就不會影響下邊線程的執行順序,那麼為什麼有這個關鍵字就會變成異步請求?我們列印一下帶有關鍵字的函數看一下:
async function foo(n){
return n
}
console.log(foo(222))
控制台會列印出這樣:

會神奇的發現,列印出來的是一個帶有Promise對象,并且resolved完成狀态,結果傳回了222。
是以,async函數是包裝成了Promise對象作為的傳回值 => Promise.resolve(value)
await是等待的意思,放在要異步操作的方法前邊。在異步函數當中,等待一段要發生的代碼,傳回後再向下執行,在沒傳回值之前,目前異步函數中await後的代碼暫不執行。我們看兩個重要的例子,仔細看一下:
// 随便寫一個延遲函數
function result() {
setTimeout(() => {
console.log('異步請求')
}, 2000);
}
// 然後使用這個方法,先用一個await
async function foo(){
console.log('111')
await result();
console.log('222');
}
foo()
console.log('333')
列印結果如上,函數照常執行,是以先列印了111,然後遇到了await等待關鍵字,發起了異步請求,是以222是在333之後列印的,在等待2秒之後,最後列印出“異步請求”。
那麼如果我把await關鍵字去掉會怎麼樣?
// 随便寫一個延遲函數
function result() {
setTimeout(() => {
console.log('異步請求')
}, 2000);
}
// 然後使用這個方法,先用一個await
async function foo(){
console.log('111')
result();
console.log('222');
}
foo()
console.log('333')
結果是:
可以看出,222不再受到await影響,按照了111、222、333正常列印。
問題來了:
- 那await加與不加有什麼用呢?2秒鐘後不都可以列印出“異步請求”四個字嗎?
- 上邊所說的 “ 在異步函數當中,await等待一段要發生的代碼,傳回後再向下執行,在沒傳回值之前,目前異步函數中await後的代碼暫不執行 ” 這句話也沒有得到驗證,222照常列印出來,又是什麼原因?
原因請注意上述代碼,result函數并不是異步函數,僅僅隻是個帶有延遲的函數,如果我更改一個result函數,加上Promise,使它成為一個異步函數,我們再來看一下:
// 此刻我們寫一個異步方法
function result() {
return new Promise((resolved,reject)=>{
setTimeout(() => {
resolved(console.log('異步請求'))
}, 2000);
})
}
// 然後使用這個方法,需要用到await
async function foo(){
console.log('111')
await result();
console.log('222');
}
foo()
console.log('333')
列印結果如下:
先列印出111和333,2秒鐘過後,列印出“異步請求”和222,是以這也是證明了 async/await 是操作異步方法,在傳回結果之前,await後的代碼,是不執行的。
async/await可以捕獲到錯誤資訊,利用try...catch,隻需要在要捕獲的地方加上這個方法即可:
function result() {
return new Promise((resolved,reject)=>{
setTimeout(() => {
reject(console.log('異步請求'))
}, 2000);
})
}
// 然後使用這個方法,需要用到await
async function foo(){
console.log('111')
try{
await result();
console.log('222');
}catch(err){
console.log(err)
}
}
foo()
console.log('333')
上邊的undefined就是錯誤資訊,隻不過這個案例沒有錯誤資訊;在實際項目中,有一些錯誤,我們就可以用這種方式捕獲到錯誤資訊,(
try...catch
語句用于處理代碼中可能出現的錯誤資訊),如果用在Promise當中,捕獲錯誤資訊就會很麻煩。這也是async的一個優點。
這樣看起來 async/await 的寫法,很像同步的寫法,但是卻可以像Promise一樣去處理異步,這就是一種代碼簡潔的好處,如果有多個異步需要處理,不再需要像Promise那樣很多
.then
代碼橫向發展,我們來做一下對比,例如有ABCD四個異步需要觸發:
Promise寫法
const result = () => {
return aaa()
.then(() => A())
.then(() => B())
.then(() => C())
.then(() => D())
}
result()
.catch(err => {
console.log(err);
})
async/await寫法
const result = async () => {
await A()
await B()
await C()
await D()
}
result()
.catch(err => {
console.log(err);
})
上述的代碼,隻是為了證明async/await寫法的可讀性會更好,我們在寫項目時,在傳回的結果中會做很多處理,這種寫法在多層嵌套中,你就會發覺它的優勢了。
以上就是簡單介紹關于async/await的用法,還有很多的用法,例如取中間值,All方法等等,同學們可以進一步去查閱資料,在實際項目中,掌握以上的關鍵的知識點,是必要的。
有興趣的同學也可以查詢async/await的原理,包括進一步學習關于generator函數,并且可以在評論區留言,共同進步。
部落客聯系方式:
e-mail:[email protected]
weChat:VillinWeChat
歡迎提出寶貴意見