es6 async函式與其他非同步處理方法的比較
阿新 • • 發佈:2019-02-05
async函式與其他非同步處理方法的比較
我們通過一個例子,來看 async函式與 Promise、Generator函式的比較。
假定某個 DOM 元素上面,部署了一系列的動畫,前一個動畫結束,才能開始後一個。如果當中有一個動畫出錯,就不再往下執行,返回上一個成功執行的動畫的返回值。
首先是 ES6 Promise 的寫法。
function chainAnimationsPromise(elem, animations){
// 變數ret用來儲存上一個動畫的返回值
let ret =null;
// 新建一個空的Promise
let p =Promise.resolve();
// 使用then方法,新增所有動畫
for(let anim of animations){
p = p.then(function(val){
ret = val;
return anim(elem);
});
}
// 返回一個部署了錯誤捕捉機制的Promise
return p.catch(function(e){
/* 忽略錯誤,繼續執行 */
}).then(function(){
return ret;
});
}
雖然 Promise 的寫法比回撥函式的寫法大大改進,但是一眼看上去,程式碼完全都是 Promise 的 API(then
、catch
等等),操作本身的語義反而不容易看出來。
接著是 Generator函式的寫法。
function chainAnimationsGenerator(elem, animations){
return spawn(function*(){
let ret =null;
try{
for(let anim of animations){
ret =yield anim(elem);
}
}catch(e){
/* 忽略錯誤,繼續執行 */
}
return ret;
});
}
上面程式碼使用 Generator函式遍歷了每個動畫,語義比 Promise 寫法更清晰,使用者定義的操作全部都出現在spawn
函式的內部。這個寫法的問題在於,必須有一個任務執行器,自動執行
Generator函式,上面程式碼的spawn
yield
語句後面的表示式,必須返回一個
Promise。
最後是 async函式的寫法。
async function chainAnimationsAsync(elem, animations){
let ret =null;
try{
for(let anim of animations){
ret = await anim(elem);
}
}catch(e){
/* 忽略錯誤,繼續執行 */
}
return ret;
}
可以看到 Async 函式的實現最簡潔,最符合語義,幾乎沒有語義不相關的程式碼。它將 Generator 寫法中的自動執行器,改在語言層面提供,不暴露給使用者,因此程式碼量最少。如果使用 Generator 寫法,自動執行器需要使用者自己提供。