[Javascript] ES7 Async Await 聖經
在ES5 時期,Javascript 開發者生活在一個地獄,,叫做Callback Hell。面對著千層 Callback Function,痛苦地 console.log 進行 Debug,消磨生命。直到ES6的降臨,Promise 被指派去拯救開發者脫離煉獄,把千層 Callback Function 扁平化,轉換成為串聯結構,Promise是黑暗隧道中的一道光。今天,Async/Await 是 Promise 的化身,降臨在ES7中。
文章內容:
備註: 文章主要討論 async/await 在處理非同步的議題.
- 必須了解的 asyncFunction
- Promise function
- Async function
- Await Sequentially
- Await Parallelly
- Await Nest
- Await Dynamically
- Error Handle
1- Constructor of async: asyncFunction
了解 async function 是什麼 Object,最好觀察它的 constructor ,呼叫一次就知道結果: asyncFunction Object (From Mozilla):
//Node.js
console.log(async function () {});// Chrome or Firefox
console.log(async function () {}.constructor);
console.log(async function () {}.__proto__);
2- Constructing Promise function
噢!又是 Promises?為什麼一篇 async/await 的文章內要穿插著大量的其他內容?因為魔鬼在細節,async/await 是背後非同步的處理其實就是 Promise。這個觀念在開發、Module 設計和臭蟲Debug 特別有幫助,當別人接手舊人的程式碼,超多一半時間都花在捕捉臭蟲。
每一個 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。
使用 async 處理非同步的 Promise function,回傳的值其實是 Resolve 的值;相似的, async exception 的結果和 Promise Reject 的結果也是一模一樣(Mozilla)。
async function asyncSleep (para){
return await sleep(para)
}var result = await asyncSleep(2)
//result is 4asyncSleep(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
想通過 Promise 來解決 Dynamic 運算的問題并不容易,往往需要改變䇿略或安裝其他 Module。雖然 Async/Await 的功能強大,但是對處理 Dynamic 的問題也沒有現成的方法。
目前的解決方法是,加入 ES6 的新功能 map(),在儲存 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
錯誤處理的聲音實在安靜,安靜得聽不見 (Nolan Lawson)
上面是一句在 Nolan Lawson 文章內名句,我非常認同。
同媽生下的 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 的貢獻在語法上為 Javascripte 進行大優化,原本執行多行 Promises 程式簡化成一行,不僅僅提高程式的可讀性,也是為 functional programming 量身訂造的設計。
壞處
正如第7和8部份提到,Promises 在處理 Dynamic Asynchronize 沒問題沒有進步。只能透過較迂迴的路,使用其他 iterable 方法分別儲存 parameters和 function 。
Async/Await 的另一個問題,錯誤處理的聲音實在太安靜,聽不見。開發者多麼希望,當 Error發生時,JS 能夠大聲大聲的呼叫我!
喜歡這篇文章嗎? 你覺得對其他人有幫助嗎? 請分享給你的朋友和讓我知道你喜歡這類型的文章, 按下面的讚。