對generator不熟悉的可以先看下相關的基礎資料
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator
在早些時候,generator + promise 可以比較優雅的解決JS中較爲頭痛的回調嵌套問題,並且爲了解決讓 generator 能夠自動執行的問題,出現了諸如co這樣的模塊,在這裏自己簡單的實現一版,探索一下其中的原理,首先要解決幾個問題。
-
自執行
自執行的關鍵就是要在每一個異步的回調中,去調用iterator的next方法,並且傳入相應回調的參數。用遞歸的思路可以較好解決,這裏要注意的是,yield 後面可以跟上同步操作,這種情況我也統一包裝成了promise返回。 -
yield 後面跟的是一個promise數組
當有多個異步任務時,這裏會利用Promise.all 來處理這個情況,最終返回一個結果數組,注意下 promise 數組的判斷就好。 -
在這個自執行方法執行完後,需要返回一個promise,可以繼續調用then方法,這個只需要在最開始返回一個promise即可。
示例如下
function run (genFn) {
let it = genFn();
let store = it.next();
return new Promise((resolve,reject)=>{
function next () {
if (store.done) resolve(store.value);
// 如果是promise數組
if (isPromiseArray(store.value)){
Promise.all(store.value).then((retArray)=>{
store = it.next(retArray);
next();
}).catch(e => reject(e.message));
} else {
// 因爲每一個步驟可能是異步,也可能是同步,這裏統一轉化爲Promise來處理
if (!(store.value instanceof Promise)) store.value = Promise.resolve(store.value).catch((e => console.log(e.message)));
store.value.then((ret) => {
store = it.next(ret);
next();
}).catch(e => reject(e.message));
}
}
function checkType(variable){
return Object.prototype.toString.call(variable).slice(8,-1).toLowerCase();
}
function isPromiseArray (array) {
if (!(checkType(array) === 'array')) return false
let flag = true;
for (let i=0; i<array.length;i++) {
if (!(array[i] instanceof Promise)){
flag = false;
break;
}
}
return flag;
}
next();
});
}