這纔是tapable裏面SyncLoopHook鉤子函數的實現

前言

webpack的都知道,webpack把各個插件串聯起來的核心是tapable,而tapable裏面有不少*hook函數,其中有一個不經常使用,可是卻很好玩的鉤子函數叫 SyncLoopHook, 因而我就本身實現了一遍, 而後想去和網友對比一下實現的不一樣。誰知道,網上不少SyncLoopHook函數的實現都是同樣的,並且仍是錯的webpack

1. 網上廣泛的SyncLoopHook

class SyncLoopHook{
    constructor() {
        this.tasks=[];
    }
    tap(name,task) {
        this.tasks.push(task);
    }
    call(...args) {    
        this.tasks.forEach(task => {
            let ret=true;
            do {
                ret = task(...args);
            }while(ret)
        });
    }
}
複製代碼

網上大部分都是這樣實現的, 這樣寫只是把returnundefind的回調函數循環執行web


以下圖, 第一個回調函數執行了兩遍,沒問題bash

可是把 return放到第二個以後的就會出錯了,它只是把第二個回調函數執行兩次

tapable裏的 SyncLoopHook是把包括 returnundefined的回調函數和該回調函數以前的回調函數都循環一遍, 以下圖

2. 個人SyncLoopHook

注意 : SyncLoopHook只能有一次循環, 若是不對, 請及時告訴我函數

class SyncLoopHook {
    constructor () {
        this.tasks = []
    }
    tap (...args) {
        this.tasks.push(args.pop())
    }
    call (...args) {
        let ret,
            alreadyLoop = false  // 是否已經循環了

        this.tasks.reduce( (baton, task)  => {
            baton.push(task)
            
            // 判斷最新一個回調函數的返回值
            ret = baton[baton.length - 1](...args)
            
            // 若是返回值爲undefined 且 若是已經循環了, 返回[], 若是還沒循環, 返回包含上一個回調的baton
            if (!ret) return alreadyLoop ? [] : baton
            
            // 若是不是undefine,遍歷baton並檢測最後一個回調函數的返回值,直到爲undefined
            while (ret) ret = baton.map(e => e(...args)).pop()
            
            // 代碼執行到這裏,證實已經循環了
            alreadyLoop = true
        
            // 已經循環了,清空baton
            return []
        }, [])
    }
}

複製代碼


有時候網上的東西也不能全信,仍是要本身寫一遍才行~oop

相關文章
相關標籤/搜索