這才是tapable裡面SyncLoopHook鉤子函式的實現

xuyede發表於2019-04-03
前言

webpack的都知道,webpack把各個外掛串聯起來的核心是tapable,而tapable裡面有很多*hook函式,其中有一個不常用,但是卻很好玩的鉤子函式叫 SyncLoopHook, 於是我就自己實現了一遍, 然後想去和網友對比一下實現的不同。誰知道,網上很多SyncLoopHook函式的實現都是一樣的,而且還是錯的

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的回撥函式迴圈執行


如下圖, 第一個回撥函式執行了兩遍,沒問題

這才是tapable裡面SyncLoopHook鉤子函式的實現
但是把return放到第二個之後的就會出錯了,它只是把第二個回撥函式執行兩次

這才是tapable裡面SyncLoopHook鉤子函式的實現
tapable裡的SyncLoopHook是把包括returnundefined的回撥函式和該回撥函式之前的回撥函式都迴圈一遍, 如下圖
這才是tapable裡面SyncLoopHook鉤子函式的實現

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 []
        }, [])
    }
}

複製程式碼

這才是tapable裡面SyncLoopHook鉤子函式的實現
這才是tapable裡面SyncLoopHook鉤子函式的實現


有時候網上的東西也不能全信,還是要自己寫一遍才行~

相關文章