寫一個簡單的generator執行器

對generator不熟悉的可以先看下相關的基礎資料

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator

在早些時候,generator + promise 可以比較優雅的解決JS中較爲頭痛的回調嵌套問題,並且爲了解決讓 generator 能夠自動執行的問題,出現了諸如co這樣的模塊,在這裏自己簡單的實現一版,探索一下其中的原理,首先要解決幾個問題。
  1. 自執行
    自執行的關鍵就是要在每一個異步的回調中,去調用iterator的next方法,並且傳入相應回調的參數。用遞歸的思路可以較好解決,這裏要注意的是,yield 後面可以跟上同步操作,這種情況我也統一包裝成了promise返回。

  2. yield 後面跟的是一個promise數組
    當有多個異步任務時,這裏會利用Promise.all 來處理這個情況,最終返回一個結果數組,注意下 promise 數組的判斷就好。

  3. 在這個自執行方法執行完後,需要返回一個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();
    });
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章