一路上感謝各位讀者們的支持和回饋。
本 30 天系列文目前已經將篇幅重新整理、編纂成冊。
《JavaScript 概念三明治》在天瓏書局上架囉!
喜歡這個系列,想閱讀更詳細原理說明的讀者可以參考:
https://www.tenlong.com.tw/products/9789864347575
Promise 讓我們有一個可以很方便寫出非同步函式的方法,不過像這樣非同步的程式碼對於我們在閱讀或是 Debug 要判斷執行的先後順序上可能會比較不值觀,今天要來介紹一組讓 Promise 程式碼的可讀性大大提升的語法糖:Async / Await。
常常我們在拉 API 的時候會以 Promise 的方式來實作(例如 axios ),而在這個 Promise 裡的 Callback ,如果又想拉取另外一支 API ,就會需要執行另外一個 Promise , 結果就寫出了難以閱讀的程式碼:
let promise = new Promise (( resolve, reject)⇒{
resolve('some value')
})
promise.then((value)⇒{
let promise2 = new Promise((resolve,reject)=>{
resolve('value2')
})
promise2.then((value2)=>{
...
})
})
這樣子的寫法可能少少幾行還沒事,但當專案變大之後,如果充滿了這樣子的程式碼,那肯定讓你眼花撩亂,所以我們需要 async / await 來做簡化。
async
語法必須寫在函式宣告前面,用來告訴 JS 這個函式是一個非同步的函式,就像這樣:
async function asyncFunc() {
return "Hey!";
}
asyncFunc() // will get a resolved promise.
而用 async
語法所宣告的函式,被呼叫時永遠都會回傳一個 Promise,雖然從上述程式碼看不出來,但是 JS 程式碼會幫你用 Promise 然後包起來回傳給你,就像這樣:
function asyncFunc (){
return new Promise((resolve,reject)=>{
resolve("Hey!")
})
}
await
只能使用在 async
函式內部,在這之外的地方使用的話就會報錯。在 async 函式內部,如果還有其他非同步的程式碼,例如在裡面寫 Promise ,我們就可以用 await
,去告訴 JS 引擎要停下來等待這個非同步程式碼執行完畢,並且等到 Promise 被 resolve 之後才會繼續往下執行。
async function asyncFunc() {
let data = await new Promise((resolve,reject)=>{
// do some calculation
resolve('api data')
})
console.log(data) //'api data'
}
有了 await
之後我們就可以寫出非常容易閱讀的程式碼, async
關鍵字也很明確告訴你這個韓式內有非同步的程式碼,而如果沒有 await
我們原本還需要透過 .then 函式才能拿到 Promise 執行完畢 resolve 之後的值。
更棒的是,如果你的函式內本來有不只一個 Promise 想要依序執行,使用 await
就可以讓你的邏輯以很清楚的方式表現:
async function asyncFunc() {
let promise1 = await new Promise((resolve,reject)=>{
// do some calculation
resolve('api data')
})
let promise2 = await new Promise((resolve,reject)=>{
// get res data of promise1 and do some thing
resolve('success!')
})
console.log(promise2) //'success'
}
不過有一個小缺點是因為使用 await
的話,因為 JS 引擎會一直等待 Promise 執行完畢,所以如果過度濫用的話,那就失去非同步的意義了,這點在使用時要多多注意,自己斟酌。
使用 async / await 這個語法糖時,為了讓錯誤處理也變得更簡潔,可以搭配 try / catch 使用:
async function asyncFunc() {
try{
let data = await new Promise((resolve,reject)=>{
// do some calculation
resolve('api data')
})
console.log(data) //'api data'
}catch(e){
console.log('error',e)
}
}