深切明白Webpack中心模块Tapable钩子[同步版]

纪录下本身在前端路上爬坑的阅历 加深印象,正文最先~

tapable是webpack的中心依靠库 想要读懂webpack源码 就必须起首熟习tapable
ok.下面是webapck中引入的tapable钩子 因而可知 在webpack中tapable的重要性

const {
    SyncHook,
    SyncBailHook,
    SyncWaterfallHook,
    SyncLoopHook,
    AsyncParallelHook,
    AsyncParallelBailHook,
    AsyncSeriesHook,
    AsyncSeriesBailHook,
    AsyncSeriesWaterfallHook
 } = require("tapable");

这些钩子可分为同步的钩子和异步的钩子,Sync开首的都是同步的钩子,Async开首的都是异步的钩子。而异步的钩子又可分为并行和串行,实在同步的钩子也能够明白为串行的钩子。

本文将依据以下章节离别梳理每一个钩子

同步钩子

  • SyncHook
  • SyncBailHook
  • SyncWaterfallHook
  • SyncLoopHook

起首装置tapable
npm i tapable -D

SyncHook

SyncHook是简朴的同步钩子,它很相似于宣布定阅。起首定阅事宜,触发时根据递次顺次实行,所以说同步的钩子都是串行的。

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

class Hook{
    constructor(){
        /** 1 天生SyncHook实例 */
        this.hooks = new SyncHook(['name']);
    }
    tap(){
        /** 2 注册监听函数 */
        this.hooks.tap('node',function(name){
            console.log('node',name);
        });
        this.hooks.tap('react',function(name){
            console.log('react',name);
        });
    }
    start(){
        /** 3动身监听函数 */
        this.hooks.call('call end.');
    }
}

let h = new Hook();

h.tap();/** 相似定阅 */ 
h.start();/** 相似宣布 */

/* 打印递次:
    node call end.
    react call end.
*/

能够看到 它是根据递次顺次打印的,实在说白了就是宣布和定阅。接下来我们就手动完成它。

class SyncHook{ // 定义一个SyncHook类
    constructor(args){ /* args -> ['name']) */
        this.tasks = [];
    }
    /** tap吸收两个参数 name和fn */
    tap(name,fn){
        /** 定阅:将fn放入到this.tasks中 */
        this.tasks.push(fn);
    }
    start(...args){/** 接收参数 */
        /** 宣布:将this.taks中的fn顺次实行 */
        this.tasks.forEach((task)=>{
            task(...args);
        });
    }
}

let h = new SyncHook(['name']);

/** 定阅 */
h.tap('react',(name)=>{
    console.log('react',name);
});
h.tap('node',(name)=>{
    console.log('node',name);
});
/** 宣布 */
h.start('end.');

/* 打印递次:
    react end.
    node end.
*/

SyncBailHook

SyncBailHook 从字面意义上明白为带有保险的同步的钩子,带有保险意义是 依据每一步返回的值来决议要不要继承往下走,假如return了一个非undefined的值 那就不会往下走,注重 假如什么都不return 也相当于return了一个undefined。

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

class Hook{
    constructor(){
        this.hooks = new SyncBailHook(['name']);
    }
    tap(){
        this.hooks.tap('node',function(name){
            console.log('node',name);
            /** 此处return了一个非undefined
             *  代码到这里就不会继承实行余下的钩子
             */
            return 1;
        });
        this.hooks.tap('react',function(name){
            console.log('react',name);
        });
    }
    start(){
        this.hooks.call('call end.');
    }
}

let h = new Hook();

h.tap();
h.start();

/* 打印递次:
    node call end.
*/

手动完成

class SyncHook{
    constructor(args){ 
        this.tasks = [];
    }
    tap(name,fn){
        this.tasks.push(fn);
    }
    start(...args){
        let index = 0;
        let result;
        /** 应用do while先实行一次的特征 */
        do{
            /** 拿到每一次函数的返回值 result */
            result = this.tasks[index++](...args);
            /** 假如返回值不为undefined或许实行终了一切task -> 中缀轮回 */
        }while(result === undefined && index < this.tasks.length);
    }
}

let h = new SyncHook(['name']);

h.tap('react',(name)=>{
    console.log('react',name);
    return 1;
});
h.tap('node',(name)=>{
    console.log('node',name);
});

h.start('end.');

/* 打印递次:
   react end.
*/

SyncWaterfallHook

SyncWaterfallHook是同步的瀑布钩子,瀑布怎样明白呢? 实在就是说它的每一步都依靠上一步的实行效果,也就是上一步return的值就是下一步的参数。

const { SyncWaterfallHook } = require('tapable');

class Hook{
    constructor(){
        this.hooks = new SyncWaterfallHook(['name']);
    }
    tap(){
        this.hooks.tap('node',function(name){
            console.log('node',name);
            /** 此处返回的值作为第二步的效果 */
            return '第一步返回的效果';
        });
        this.hooks.tap('react',function(data){
            /** 此处data就是上一步return的值 */
            console.log('react',data);
        });
    }
    start(){
        this.hooks.call('callend.');
    }
}

let h = new Hook();

h.tap();
h.start();

/* 打印递次:
    node callend.
    react 第一步返回的效果
*/

手动完成:

class SyncWaterFallHook{
    constructor(args){
        this.tasks = [];
    }
    tap(name,fn){
        this.tasks.push(fn);
    }
    start(...args){
        /** 解构 拿到tasks中的第一个task -> first */
        let [first, ...others] = this.tasks;
        /** 应用reduce() 累计实行 
         * 起首传入第一个 first 并实行
         * l是上一个task n是当前task
         * 如许满足了 下一个函数依靠上一个函数的实行效果
        */
        others.reduce((l,n)=>{
            return n(l);
        },first(...args));
    }
}

let h = new SyncWaterFallHook(['name']);

/** 定阅 */
h.tap('react',(name)=>{
    console.log('react',name);
    return '我是第一步返回的值';
});
h.tap('node',(name)=>{
    console.log('node',name);
});
/** 宣布 */
h.start('end.');

/* 打印递次:
    react end.
    node 我是第一步返回的值
*/

SyncLoopHook

SyncLoopHook是同步的轮回钩子。 轮回钩子很好明白,就是在满足肯定前提时 轮回实行某个函数:

const { SyncLoopHook } = require('tapable');

class Hook{
    constructor(){
        /** 定义一个index */
        this.index = 0;
        this.hooks = new SyncLoopHook(['name']);
    }
    tap(){
        /** 箭头函数 绑定this */
        this.hooks.tap('node',(name) => {
            console.log('node',name);
            /** 当不满足前提时 会轮回实行该函数 
             * 返回值为udefined时 停止该轮回实行
            */
            return ++this.index === 5?undefined:'学完5遍node后再学react';
        });
        this.hooks.tap('react',(data) => {
            console.log('react',data);
        });
    }
    start(){
        this.hooks.call('callend.');
    }
}

let h = new Hook();

h.tap();
h.start();

/* 打印递次:
    node callend.
    node callend.
    node callend.
    node callend.
    node callend.
    react callend.
*/

能够看到 实行了5遍node callend后再继承往下实行。也就是当返回undefined时 才会继承往下实行:

class SyncWaterFallHook{
    constructor(args){
        this.tasks = [];
    }
    tap(name,fn){
        this.tasks.push(fn);
    }
    start(...args){
        let result;
        this.tasks.forEach((task)=>{
            /** 注重 此处do{}while()轮回的是每一个零丁的task */
            do{
                /** 拿到每一个task实行后返回的效果 */
                result = task(...args);
                /** 返回效果不是udefined时 会继承轮回实行该task */
            }while(result !== undefined);
        });
    }
}

let h = new SyncWaterFallHook(['name']);
let total = 0;
/** 定阅 */
h.tap('react',(name)=>{
    console.log('react',name);
    return ++total === 3?undefined:'继承实行';
});
h.tap('node',(name)=>{
    console.log('node',name);
});
/** 宣布 */
h.start('end.');

/* 打印递次:
    react end.
    react end.
    react end.
    node end.
*/

能够看到, 实行了3次react end.后 才继承实行了下一个task -> node end。至此,我们把tapable的一切同步钩子都剖析终了. 异步钩子比同步钩子贫苦些,我们会在下一章节最先剖析异步的钩子.

传送门:深切明白Webpack中心模块Tapable钩子(异步版)

代码:mock-webpack-tapable

    原文作者:Funky_Tiger
    原文地址: https://segmentfault.com/a/1190000018312127
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞