假定某個(gè) DOM 元素上面,部署了一系列的動(dòng)畫茫因,前一個(gè)動(dòng)畫結(jié)束蚪拦,才能開始后一個(gè)。如果當(dāng)中有一個(gè)動(dòng)畫出錯(cuò),就不再往下執(zhí)行驰贷,返回上一個(gè)成功執(zhí)行的動(dòng)畫的返回值盛嘿。
首先是 Promise 的寫法。
function chainAnimationsPromise(elem, animations) {
// 變量ret用來保存上一個(gè)動(dòng)畫的返回值
let ret = null;
// 新建一個(gè)空的Promise
let p = Promise.resolve();
// 使用then方法括袒,添加所有動(dòng)畫
for(let anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
});
}
// 返回一個(gè)部署了錯(cuò)誤捕捉機(jī)制的Promise
return p.catch(function(e) {
/* 忽略錯(cuò)誤次兆,繼續(xù)執(zhí)行 */
}).then(function() {
return ret;
});
}
雖然 Promise 的寫法比回調(diào)函數(shù)的寫法大大改進(jìn),但是一眼看上去锹锰,代碼完全都是 Promise 的 API(then芥炭、catch等等),操作本身的語義反而不容易看出來恃慧。
接著是 Generator 函數(shù)的寫法园蝠。
function chainAnimationsGenerator(elem, animations) {
return spawn(function*() {
let ret = null;
try {
for(let anim of animations) {
ret = yield anim(elem);
}
} catch(e) {
/* 忽略錯(cuò)誤,繼續(xù)執(zhí)行 */
}
return ret;
});
}
上面代碼使用 Generator 函數(shù)遍歷了每個(gè)動(dòng)畫痢士,語義比 Promise 寫法更清晰彪薛,用戶定義的操作全部都出現(xiàn)在spawn函數(shù)的內(nèi)部。這個(gè)寫法的問題在于怠蹂,必須有一個(gè)任務(wù)運(yùn)行器善延,自動(dòng)執(zhí)行 Generator 函數(shù),上面代碼的spawn函數(shù)就是自動(dòng)執(zhí)行器褥蚯,它返回一個(gè) Promise 對象挚冤,而且必須保證yield語句后面的表達(dá)式况增,必須返回一個(gè) Promise赞庶。
最后是 async 函數(shù)的寫法。
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(let anim of animations) {
ret = await anim(elem);
}
} catch(e) {
/* 忽略錯(cuò)誤澳骤,繼續(xù)執(zhí)行 */
}
return ret;
}
可以看到 Async 函數(shù)的實(shí)現(xiàn)最簡潔歧强,最符合語義,幾乎沒有語義不相關(guān)的代碼为肮。它將 Generator 寫法中的自動(dòng)執(zhí)行器摊册,改在語言層面提供,不暴露給用戶颊艳,因此代碼量最少茅特。如果使用 Generator 寫法,自動(dòng)執(zhí)行器需要用戶自己提供棋枕。`