前言
前接JavaScript – Promise,Promise
提供了一個異步操作的方式,但寫法仍然略為複雜;而async
及await
就是為了簡化Promise
而產生的。
async
及await
簡介
先簡單說明async
及await
。
async
- 加在
function
之前。 - 該
function
會自動被包成一個Promise
來執行。 - 若有
return
值,會被放在Promise.resolve
裡再回傳
await
- 僅能用在有加
async
的function
之中。 - 對象是
Promise
或Thenable
- 會等待
Promise
執行完再繼續執行後續的程式。
實例
以一個經常使用的場景來說明,在畫面載入大量資料時,會先使用圖示或文字在畫面上提示Loading
並將系統變為載入中的狀態
,然後透過AJAX取得資料後顯示資料
,再通知系統變為載入完成的狀態
,以便去除載入圖示或文字。
基本想法
上述的場景,如果寫成程式可能是下列這樣子
function normalLoadTodos() {
console.log("1. ---Normal Loading---");
fetch(API)
.then(response => response.json())
.then(data => {console.log("2. Normal [Data] - "+data)});
console.log("3. ---Normal Loading Finished---");
}
但實際執行的結果可能會是
1. ---Normal Loading---
3. ---Normal Loading Finished---
2. Normal [Data] - [object Object]
步驟2因為是異步執行,所以比較慢,而步驟3已經做完了,造成去除了載入文字但沒有資料可用的問題。
使用then
根據上面的問題,很快就想到,如果把步驟3放在步驟2的then
裡,就可以解決了。
function normalLoadTodos2() {
console.log("1. ---Normal Loading---");
fetch(API)
.then(response => response.json())
.then(data => {console.log("2. Normal [Data] - "+data)})
.then(()=> console.log("3. ---Normal Loading Finished---"));
}
的確,執行的結果就會如我們所想,依序執行
1. ---Normal Loading---
2. Normal [Data] - [object Object]
3. ---Normal Loading Finished---
但如果在fetch
後續有很多行程式呢?那then
就會一直then
下去囉。
改用async及await
再來就看看async
及await
能簡化程式到什麼樣的地步
async function asyncLoadTodos() {
console.log("1. ---Async Loading---");
await fetch(API)
.then(response => response.json())
.then(data => {console.log("2. Async [Data] - "+data)});
console.log("3. ---Async Loading Finished---");
}
第一步,在function
前加上async
async function asyncLoadTodos() {
....
}
第二步,在fetch
前加上await
async function asyncLoadTodos() {
...
await fetch(API)
...
}
因為fetch
會回傳Promise
物件,所以是await
可用的對象,而要用await
,在外層的function
必需要加上async
。
而執行結果就如預期般地依序執行
1. ---Async Loading---
2. Async [Data] - [object Promise]
3. ---Async Loading Finished---
再簡化
觀察一下,可以發現fetch
後的then
,都沒有異步執行的問題,所以可以再拿出來
async function asyncLoadTodos2() {
console.log("1. ---Async Loading---");
let response = await fetch(API);
let data = response.json();
console.log("2. Async [Data] - "+data);
console.log("3. ---Async Loading Finished---");
}
把所有then
都移除了,看起來的確容易多囉。
比較
比較兩種版本
function normalLoadTodos2() {
console.log("1. ---Normal Loading---");
fetch(API)
.then(response => response.json())
.then(data => {console.log("2. Normal [Data] - "+data)})
.then(()=> console.log("3. ---Normal Loading Finished---"));
}
async function asyncLoadTodos2() {
console.log("1. ---Async Loading---");
let response = await fetch(API);
let data = response.json();
console.log("2. Async [Data] - "+data);
console.log("3. ---Async Loading Finished---");
}
哪一種比較容易懂呢?