ES7 - Async 與 Await
Async、Await 最主要的特點就是可以依照順序逐個執行 Ajax 請求。
Async 的實體是一個 function,這個 function 會回傳一個 Promise 物件,如果 function 有 return 內容,則回傳的 Promise 物件會取得 resolve 的內容,有發生錯誤的話,則是回傳 reject 的狀態及錯誤訊息。也因為它是 function 的關係,可把非同步相關的程式碼都集中在一起,更好做管理。
而 Await 在 Async function 中扮演著非常重要的角色,它會負責控管當下 Promise 請求的進度,等到當前的 Promise 回傳完成後(不論成功或失敗),才進行下一步。
const getAllDatas = async (id1, id2)=>{
const data1 = await fetch(`https://randomuser.me/api/?id=${id1}`).then(data=>data.json());
console.log(data1);
const data2 = await fetch(`https://randomuser.me/api/?id=${id2}`).then(data=>data.json());
console.log(data1, data2);
}
getAllDatas(1,2);
以範例來說, getAllDatas()
是一個 Async function,其中 async
語法要寫在 function 的最開頭讓 JavaScript 知道它與一般 function 不同,function 中則直接撰寫非同步程式,執行 Ajax 的程式開頭加上 await
以告知這段程式需要暫停並等待完成。使用變數存放 await 的 Ajax,回傳結果會直接返回變數身上,因此在該 function 中就可以直接取得 data。
而錯誤訊息的捕獲則是使用 try catch
語法來幫忙,將要執行的一系列 Ajax 行為寫在 try block 中,如果 Ajax 有設定發生錯誤要顯示的特殊訊息,則錯誤發生時, catch block 就可取得該 error 資訊。
const getAllDatas = async (id1, id2)=>{
try{
// 假設把 data1 的 api 連結打錯
const data1 = await fetch(`https://randomuser.me/ap/?id=${id1}`).then(data=>data.json());
console.log(data1);
const data2 = await fetch(`https://randomuser.me/api/?id=${id2}`).then(data=>data.json());
console.log(data1, data2);
}catch(err){
console.log('error:' + err);
}
}
getAllDatas(1,2); //error: SyntaxError: Unexpected token N in JSON at position 0
Async/Await 乍看可能跟 Promise.all() 很像,但其實運行方式不同,前者在執行非同步程式時是一步一步的,會等待步驟完成才繼續下一步,而 Promise.all() 則是在執行的當下就各自跑呼叫的 api,但會等到全部的 api 都回傳資訊後才一起將資料 pass 回來。
const getAllDatas = async ()=>{
const gender = await new Promise(res=>{
setTimeout(()=>{ res('female') }, 1000);
})
const data = await fetch(`https://randomuser.me/api/?gender=${gender}`).then(data=>data.json());
console.log(data);
}
getAllDatas();
從上例就可以知道, data
的 api 呼叫會等到 gender
的 setTimeout 跑完才執行,這當中就是有 Await 在控管的關係。
Async/Await 也可以搭配 Promise.all() 來達成同時呼叫 api。
async function runBoth(){
const apis = ['https://randomuser.me/api/', 'https://picsum.photos/list'];
const promise = apis.map(api=> fetch(api).then(res=>res.json()));
const datas = await Promise.all(promise);
console.log(datas);
}
runBoth();