[Javascript] ES7 Async Await 聖經

在ES5 時期,Javascript 開發者活在一個地獄,,叫做Callback Hell。他們每天面對著千層 Callback Function,痛苦地通過加入 console.log 進行 Debug,極度消磨生命。直到ES6,Promise 被指派去拯救開發者脫離 Callback Hell 的煉獄,這神奇的 Promise 把千層 Callback Function 扁平化,轉換成為串聯結構,Promise是隧道中又深又遠的一道光。今天,Async/Await 是 Promise 的化身,降臨在ES7中。

文章內容:

備註: 文章主要討論 async/await 在處理非同步的議題.

  1. 必須了解的 asyncFunction
  2. Promise function
  3. Async function
  4. Await Sequentially
  5. Await Parallelly
  6. Await Nest
  7. Await Dynamically
  8. Error Handle
Chronological Picture

1- Constructor of async: asyncFunction

請舉手,如果知道 async function 在宣告時發生什麼事?知道答案的人,可以跳過這個部份。這是async中最重要的觀念,去了解async function 的根本,我們透過 async function的 constructor ,觀察到底果實裏面發生什麼化學反應。

回傳的結果是,一個 asyncFunction Object (From Mozilla):

console.log(async function () {});

如下面程式所見,asyncFunction Object其實是 Promises,單純的 Promises 。基於他們是同一個媽生出來的兩兄弟的事實,我不會驚訝,如果他們的行為和樣貌很相似。例如在 Resolving ParallelError Handling 方面,async function Promises 有著一樣的性質:

function(){
...
return new Promise(function(resolve, reject) {
...
})
...
}

2- Constructing Promise function

噢!又是 Promises?為什麼在一篇聊 async/await 的文章內要穿插著大量的 其他內容?因為很多人會忽略,其實async/await 是建立在Promises 的基礎上。每一個 async 的建立和每一個 await 的等待都是 Promises.

var sleep = function(para) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(para * para)
}, 1000)
})
}
var result = await sleep(2)
// result is 4

3- Constructing Async function

通過 async function 定議的 function/Object 就是一個回傳AsyncFunction 的 Object。在使用 await 獲得 return 值時,其實一樣是 resolve 一個 promise 獲得的值。相反,一個 async function throws exception 一個值的情況,相等於 promises reject 一個值(Mozilla)。

async function asyncSleep (para){
return await sleep(para)
}
var result = await asyncSleep(2)
//result is 4
asyncSleep(3).then(function(result2){
//result2 is 9
})

4- Await Sequentially

var result1 = await sleep(2);
var result2 = await sleep(result1);
var result3 = await sleep(result2);
//result1 is 4
//result2 is 16
//result3 is 256

5- Await Parallelly

var results = await Promise.all([sleep(1), sleep(2)]);
//results is [1,4]

6- Nest

for(var i =0 ; i<3; i++){
var result = await sleep(i);
for(var j =0 ; j<result; j++){
console.log(' i:'+i+', j:'+j+': ', await sleep(j));
}
}
// i:1, j:0:  0
// i:2, j:0: 0
// i:2, j:1: 1
// i:2, j:2: 4
// i:2, j:3: 9

7- Dynamic Async functions

錯誤處理的聲音實在太小,聽不見 (Nolan Lawson).。

Nolan Lawson 文章內的上句我非常同認同,也是上面的引用。在處理 Dynamic 解決 asynchronize 的問題上,直覺上會把要執行的 Promises function 加入 Array 然後再一個接一個的 await。但是實驗結果并不如我所願,Promsies function 在加入的同時就開始執,它的開始和結束或返回值已經失去控制。

目前的解決方法是,在儲存 Promises function 的同時把 parameters 也存起來,在需要執行時再進行呼叫。

var sleep = function(para1,para2) {
var _para1 = para1, _para2 = para2 || para1 ;
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(_para1 * _para2)
}, 1000)
})
}
var proMap = new Map();
proMap.set([1], sleep);
proMap.set([2, 3], sleep);
proMap.set([3], sleep);
for (var [para, fun] of proMap.entries()) {
var result = await fun.apply(this, para);
console.log(para, result)
}
//[ 1 ] 1
//[ 2, 3 ] 6
//[ 3 ] 9

8- Error handle

Errors are swallowed “silently” within an async function – just like inside normal Promises (Nicolas Bevacqua).

同媽生下的 Async 和 Promises 在處理 Error Handling 的行為上,完全是執行同一模式,程式都必需必包在 try/catch內錯誤才能被捕獲。

var errorSleep = function(para) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(' ErrorSleep')
}, 1000)
})
}
try {
var result1 = await sleep(1);
var result2 = await errorSleep(4);
var result3 = await sleep(1);
console.log('result1: ', result1)
console.log('result2: ', result2)
console.log('result3: ', result3)
} catch (err) {
console.log('err: ', err)
console.log('result1: ', result1)
console.log('result2: ', result2)
console.log('result3: ', result3)
}
//err:   ErrorSleep
//result1: 1
//result2: undefined
//result3: undefined

Sumary:

好處

async/await 主要在語法上為 Javascripter 進行大優化,原本執行多行 Promises 程式簡化成一行,不僅僅提高程式的可讀性,也是為 functional programming 量身訂造的設計。

壞處

正如第7和8部份提到,Promises 在處理 Dynamic Asynchronize 中產生 instance并且 await 每一個所產生的 instance,并不容易。目前解決方法是走比較迂迴的路,使用多個 iterable 分開儲存 parameters和 function 并執行。Async/Await 的另一個問題,錯誤處理的聲音實在太小,聽不見。開發者多麼希望,當 Error發生時,JS 能夠大聲大聲的呼叫我!

喜歡這篇文章嗎? 你覺得對其他人有幫助嗎? 請分享給你的朋友和讓我知道你喜歡這類型的文章, 按下面的讚。