分析webpack中使用的Tapable——同步钩子实现及模拟实现

本文深入探讨webpack的核心组件Tapable,包括SyncHook、SyncBailHook、SyncWaterfallHook和SyncLoopHook四种同步钩子的用途、使用方式及实现原理,揭示webpack事件流机制的本质。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tapable

webpack本质上是一种事件流的机制,他的工作流程就是将各个插件串联起来,而实现这一切的核心就是tapable,

tapable有点类似于nodejs的events库,核心原理也是依赖于发布订阅模式:

继承了很多插件,同步的和异步的

tapable库中有3中注册方法 tap(同步注册)、tabAsync(回调cb)、tabPromise(注册是promise)

调用的三种方法 call、 callAsync、 promise

SyncHook

作用: 让添加的钩子按顺序执行
使用方式:

let {SyncHook} = require('tapable');

class Lesson {
    constructor() {
        this.hooks = {
            arch: new SyncHook(['name']),
        }
    }
    // 注册监听函数
    tap() {
        this.hooks.arch.tap('node', function(name) {
            console.log('node', name);
        });
        this.hooks.arch.tap('react', function(name) {
            console.log('react', name);
        });
    }
    start() {
        this.hooks.arch.call('zhangfeng');
    }
}

let les = new Lesson();

les.tap(); // 注册这两个事件
les.start(); // 启动钩子

实现原理:

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

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('zhangfeng');

SyncBail

作用: 如果有一个钩子返回的不是undefined,则不再往下执行;
使用方式:

let {SyncBailHook} = require('tapable');

class Lesson {
    constructor() {
        this.hooks = {
            arch: new SyncBailHook(['name']),
        }
    }
    // 注册监听函数
    tap() {
        this.hooks.arch.tap('node', function(name) {
            console.log('node', name);
            return 'node还需要加强学习'
        });
        this.hooks.arch.tap('react', function(name) {
            console.log('react', name);
        });
    }
    start() {
        this.hooks.arch.call('zhangfeng');
    }
}

let les = new Lesson();

les.tap(); // 注册这两个事件
les.start(); // 启动钩子

实现原理:

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

let hook = new SyncBailHook(['name']);

hook.tap('react', function (name) {
    console.log('react', name);
    return '到此为止'
});

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

hook.call('zhangfeng');

SyncWaterfallHook

作用: 将上一个钩子的返回值,作为下一个钩子的参数
使用方法:

let {SyncWaterfallHook} = require('tapable');
// waterfall 瀑布
class Lesson {
    constructor() {
        this.hooks = {
            arch: new SyncWaterfallHook(['name']),
        }
    }
    // 注册监听函数
    tap() {
        this.hooks.arch.tap('node', function(name) {
            console.log('node', name);
            return 'node还需要加强学习'
        });
        this.hooks.arch.tap('react', function(data) {
            console.log('react', data);
        });
    }
    start() {
        this.hooks.arch.call('zhangfeng');
    }
}

let les = new Lesson();

les.tap(); // 注册这两个事件
les.start(); // 启动钩子

实现原理:

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

let hook = new SyncWaterfallHook(['name']);

hook.tap('react', function (name) {
    console.log('react', name);
    return '到此为止'
});

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

hook.call('zhangfeng');

SyncLoopHook

作用:如果一个钩子返回不是undefined,则继续执行该钩子
使用方法:

let {SyncLoopHook} = require('tapable');
// 遇到某个不返回undefined的监听函数,会多次执行
class Lesson {
    constructor() {
        this.index = 0;
        this.hooks = {
            arch: new SyncLoopHook(['name']),
        }
    }
    // 注册监听函数
    tap() {
        this.hooks.arch.tap('node', (name) => {
            console.log('node', name);
            return ++this.index === 3 ? undefined : 'node还需要加强学习';
        });
        this.hooks.arch.tap('react', (name) => {
            console.log('react', name);
        });
    }
    start() {
        this.hooks.arch.call('zhangfeng');
    }
}

let les = new Lesson();

les.tap(); // 注册这两个事件
les.start(); // 启动钩子

实现原理:

class SyncLoopHook {    // 钩子是同步的
    constructor(args) { // args => ['name']
        this.tasks = [];
    }
    call(...args) {
        this.tasks.forEach(task => {
            let ret;
            do {
                ret = task(...args);
            } while (ret!==undefined);
        })
    }
    tap(name, task) {
        this.tasks.push(task);
    }
}

let hook = new SyncLoopHook(['name']);
let total = 0;
hook.tap('react', function (name) {
    console.log('react', name);
    return ++total === 3 ? undefined : '继续学习react';
});

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

hook.call('zhangfeng');

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值