上一章我們說過了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函數,並且可以在評論區留言,共同進步。
weChat:VillinWeChat
歡迎提出寶貴意見