[webpack]深入学习webpack核心模块tapable

一、手动实现同步钩子函数

1、SyncHook

class SyncHook {
    // 钩子是同步的
    constructor(args){
        this.tasks = [];
    }
    tap(name,task){
        this.tasks.push(task)
    }
    call(...args){
        this.tasks.forEach(
            (task)=>task(...args)
        )
    }
}

// 绑定事件就是订阅
let hook = new SyncHook(['name']);

hook.tap('react',function (name) {
    console.log('react',name)
});
hook.tap('node',function (name) {
    console.log('node',name)
});

hook.call('dellyoung');

 

2、SyncWaterfallHook

class SyncWaterfallHook {
    // 钩子是同步的
    constructor(args){
        this.tasks = [];
    }
    tap(name,task){
        this.tasks.push(task)
    }
    call(...args){
        let [first,...others] = this.tasks;
        let ret = first(...args);
        others.reduce(
            (a,b)=>{
                // a 上一个 b 下一个
                return b(a);
            },ret
        )
    }
}

// 绑定事件就是订阅
let hook = new SyncWaterfallHook(['name']);

hook.tap('react',function (name) {
    console.log('react1',name);
    return 'reactOk'
});

hook.tap('node',function (name) {
    console.log('node2',name);
    return 'nodeOk'
});

hook.tap('webpack',function (name) {
    console.log('webpack',name)
});

hook.call('dellyoung');

 

3、SyncLoopHook

class SyncLoopHook {
    // 钩子是同步的
    // 只要返回不是undefined就会一直循环
    constructor(args){
        this.tasks = [];
    }
    tap(name,task){
        this.tasks.push(task)
    }
    call(...args){
        this.tasks.forEach(
            task=>{
                let ret;
                do {
                    ret = task(...args)
                }while (ret !== undefined)
            }
        )
    }
}

// 绑定事件就是订阅
let hook = new SyncLoopHook(['name']);
let total = 0;

hook.tap('react',function (name) {
    console.log('react',name);
    return ++total === 3?undefined:'继续学'
});

hook.tap('node',function (name) {
    console.log('node',name);
});

hook.tap('webpack',function (name) {
    console.log('webpack',name)
});

hook.call('dellyoung');

 

4、SyncBailHook

class SyncBailHook {
    // 钩子是同步的
    constructor(args){
        this.tasks = [];
    }
    tap(name,task){
        this.tasks.push(task)
    }
    call(...args){
        let ret; // 当前函数返回值
        let index=0; // 先执行第一个
        do{
            ret = this.tasks[index++](...args)
        }while (ret === undefined && index < this.tasks.length);
    }
}

// 绑定事件就是订阅
let hook = new SyncBailHook(['name']);

hook.tap('react',function (name) {
    console.log('react1',name);
    // return '停止'
});
hook.tap('node',function (name) {
    console.log('node2',name)
});

hook.call('dellyoung');

  

二、手动实现异步钩子函数

1、AsyncParallelBailHook

类似promise.all[]

class AsyncParallelBailHook {
    // 钩子是同步的
    // 只要返回不是undefined就会一直循环
    constructor(args){
        this.tasks = [];
    }
    tapAsync(name,task){
        this.tasks.push(task)
    }
    callAsync(...args){
        let finalCallBack  = args.pop(); // 拿出最终的函数
        let index = 0;
        let done = () => {
            index++;
            if(index === this.tasks.length){
                finalCallBack();
            }
        };
        this.tasks.forEach(task=>{
            task(...args,done)
        })
    }
}

// 绑定事件就是订阅
let hook = new AsyncParallelBailHook(['name']);

hook.tapAsync('react',function (name,callback) {
    setTimeout(()=>{
            console.log('react',name);
            callback();
        },5000
    );
});

hook.tapAsync('node',function (name,callback) {
    setTimeout(()=>{
            console.log('node',name);
            callback();
        },1000
    );
});

hook.callAsync('dellyoung',function () {
    console.log('newBegin')
});

promise版本的AsyncParallelBailHook

class AsyncParallelBailHook {
    // 钩子是同步的
    // 只要返回不是undefined就会一直循环
    constructor(args) {
        this.tasks = [];
    }

    tabPromise(name, task) {
        this.tasks.push(task)
    }

    promise(...args) {
        let tasks = this.tasks.map(
            (task) => {
                return task(...args)
            }
        );
        // let tasks = this.tasks.map(task => task(...args));
        return Promise.all(tasks);
    }
}

// 绑定事件就是订阅
let hook = new AsyncParallelBailHook(['name']);

hook.tabPromise('react', function (name) {
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => {
                    console.log('react', name);
                    resolve();
                }, 1000
            );
        }
    )
});

hook.tabPromise('node', function (name) {
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => {
                    console.log('node', name);
                    resolve();
                }, 2000
            );
        }
    )
});

hook.promise('dellyoung').then(function () {
    console.log('newBegin')
});

2、AsyncSeriesHook

异步串行

class AsyncSeriesHook {
    constructor(args) {
        this.tasks = [];
    }

    tabAsync(name, task) {
        this.tasks.push(task)
    }

    callAsync(...args) {
        let finalCallBack = args.pop();
        let index = 0;
        let next = () => {
            if(this.tasks.length === index){
                return finalCallBack();
            }
            let task = this.tasks[index++];
            task(...args, next);
        };
        next();
    }
}

// 绑定事件就是订阅
let hook = new AsyncSeriesHook(['name']);

hook.tabAsync('react', function (name, callback) {
    setTimeout(() => {
            console.log('react', name);
            callback();
        }, 3000
    );
});

hook.tabAsync('node', function (name, callback) {
    setTimeout(() => {
            console.log('node', name);
            callback();
        }, 1000
    )
});

hook.callAsync('dellyoung',function () {
    console.log('newBegin')
});

promise版本的AsyncSeriesHook 

class AsyncSeriesHook {
    constructor(args) {
        this.tasks = [];
    }

    tabPromise(name, task) {
        this.tasks.push(task)
    }

    promise(...args) {
        // 类redux源码
        let [first,...other] = this.tasks;
        return other.reduce(
            (prom,n)=>{
                return prom.then(()=>n(...args))
            },first(...args)
        )
    }
}

// 绑定事件就是订阅
let hook = new AsyncSeriesHook(['name']);

hook.tabPromise('react', function (name) {
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => {
                    console.log('react', name);
                    resolve();
                }, 1000
            );
        }
    )
});

hook.tabPromise('node', function (name) {
    return new Promise(
        (resolve, reject) => {
            setTimeout(() => {
                    console.log('node', name);
                    resolve();
                }, 1000
            );
        }
    )
});

hook.promise('dellyoung').then(function () {
    console.log('newBegin')
});

  

 3、AsyncSeriesWaterfallHook

异步瀑布串行

class AsyncSeriesWaterfallHook {
    constructor(args) {
        this.tasks = [];
    }

    tapAsync(name, task) {
        this.tasks.push(task)
    }

    callAsync(...args) {
        let finalCb = args.pop();
        let index = 0;
        let next = (err,data) => {
            let task = this.tasks[index];
            if(!task) return finalCb();
            if(err) return ;
            if(index===0){
                // 执行第一个
                task(...args,next)
            }else {
                task(data,next)
            }
            index++;
        };
        next()
    }
}

// 绑定事件就是订阅
let hook = new AsyncSeriesWaterfallHook(['name']);

hook.tapAsync('react', function (name, cb) {
    setTimeout(() => {
            console.log('react', name);
            cb(null, 'result1');
        }, 1000
    );
});

hook.tapAsync('node', function (data, cb) {
    setTimeout(() => {
            console.log('node', data);
            cb(null);
        }, 2000
    );
});

hook.callAsync('dellyoung',function () {
    console.log('newBegin')
});

  

原文地址:https://www.cnblogs.com/piaobodewu/p/11261408.html