非同步在前端的做法不斷的在進行優化調整,先前介紹過 Promise 可以解決非同步過度巢狀的問題,而本篇要介紹的 async function(非同步函式) 及 await 則可以將非同步的程式碼寫成類似同步的形式。
Promise 本篇不會詳細介紹,如果不熟悉可以先查看 本篇 文章,Promise 與非同步函式兩者是密不可分的,雖然 async function 易讀性優於 Promise,但請先確保對於 Promise 有一定理解再來使用非同步函式。
本篇先建立一個基於 Promise 的函式,以下的範例都會不斷呼叫此函式來進行撰寫。
/**
* 範例 Promise 函式
*
* @param {數值:作為判斷非同步成功與否的條件} num
* @param {數值:非同步所執行的時間長度} [time=500]
* @returns {如果 num 為真則套用 resolve;失敗則套用 reject}
*/
function promiseFn(num, time = 500) {
return new Promise((resolve, reject) => {
setTimeout(() => {
num ? resolve(`${num}, 成功`) : reject('失敗');
}, time);
});
}
promise 函式呼叫時可以使用 then 來接收 resolve 的結果,當要串接兩個 promise 函式時可以使用 return 來做 "鏈接"。
promiseFn(1)
.then(res => {
console.log(res); // 1, 成功
return promiseFn(2); // 鏈接第二次的 Promise 方法
})
.then(res => {
console.log(res); // 2, 成功
});
基於 Promise 的方法相當單純,就是不斷的呼叫以及使用 then 來進行鏈接,當程式碼中只有呼叫 promise 函式時不會有太大問題,但如果有其它的方法需要進行運行時,就會顯得 promise 格格不入。
Promise 相當不錯,可以解決過巢及串接 callback function 語法不一致等問題,但它依然在 JS 的同步語言中插入了一段非同步的片段。

async function 可以用來定義一個非同步函式,讓這個函式本體是屬於非同步,但其內部以“同步的方式運行非同步”程式碼。
await 則是可以暫停非同步函式的運行(中止 Promise 的運行),直到非同步進入 resolve 或 reject,當接收完回傳值後繼續非同步函式的運行。

Promise 的回傳狀態,需要進入
resolve或reject後,非同步函式才會繼續運行
上述以 promise、then 寫法的程式碼,以非同步的程式碼改寫方式如下:
async function)await 暫停 promiseFn,直到回傳後再繼續向下async function getData() {
const data1 = await promiseFn(1); // 因為 await,promise 函式被中止直到回傳
const data2 = await promiseFn(2);
console.log(data1, data2); // 1, 成功 2, 成功
}
getData();
以上這段程式碼的結果與使用 then 是一致的,但就結構上更加平整,在 getData 這個函式中都是以 "同步" 的方式運行,不會產生同步、非同步混合的狀況。

無論是不是 Promise,大家都是同步程式碼逐行執行。
Async / Await 目的是讓程式碼的結構變得更加簡潔、易懂,所以運用上也如上述一樣單純(如果沒有 “錯誤”,它確實很單純),本段則額外補充說明這兩者新加入的語法是如何在 JS 中運作的。
async function 非同步函式async function 的用法相當特別,用此語法所宣告的函式,可在其內以“同步的方式運行非同步”程式碼;但就名稱上 async 是稱為非同步,那麼它的 非同步 又存在哪呢?
async function asyncFn() {
return 'a';
}
console.log(asyncFn());
非同步 稱的就是 async function 所定義的函式本體,當使用 console.log 查看 async function 那麼將可以得到與 Promise 結構相似的函式,該函式是以非同步的方式運行,無法直接使用 console.log 取得其值。

在 Promise 中,如果要取得 resolve 的結果會使用 then,而 async function 也是相同使用 then()。
asyncFn().then(r => {
console.log(r)
});
雖說如此,實戰中不太會這麼做,回到目的性來說:「
async function是讓函式內的語法同步執行」。也因為async function與一般函式定義的不同,所以請避免將所有的function前方都補上async,這會產生運行及概念上不同的函式。
await 是屬於一元運算子,它會直接回傳後方表達式的值;但如果是 Promise 時則會 “等待” resovle 的結果並回傳。
雖然是運算子,但是在原始碼中直接運行 await 則會出現錯誤,它只能在 async function 中運行,所以 async/await 基本上是一體的,不會單獨出現。
await 1;
// Uncaught SyntaxError: await is only valid in async function

比較神奇的是
await expression卻可以直接在 Chrome console 中運行。
await 可以直接回傳後方的表達式,或者將非同步函式中的 Promise 暫停,如以下範例的 await promiseFn(2) 會 “等待” resolve 結果回傳後,在賦予至 data2 才會回傳。
async function getData() {
const data1 = await 1;
const data2 = await promiseFn(2);
console.log(data1, data2); // 1 "2, 成功"
}
getData();
本篇是 async/await 兄弟的基礎介紹,接下來的章節會持續介紹關於這兩者的錯誤流程、延伸運用等技巧。