1

介绍

webpack 本身仅提供前端打包的核心流程,其他具体的打包工作依赖其生态系统中的众多插件。为此 Tapablewebpack 提供了强大而灵活的插件管理机制。Tapable 是一个用来处理 订阅 - 发布 的工具。与常见的 dom事件 添加和触发相类似。只不过在此基础之上,添加了一些处理 订阅 的特殊逻辑。

举个例子:

import { SyncHook } from 'tapable';

// 创建钩子对象
const handleElephant = new SyncHook();

// 订阅
handleElephant.tap('step1', () => console.log('1. 把冰箱门打开'));
handleElephant.tap('step2', () => console.log('2. 大象塞进去'));
handleElephant.tap('step3', () => console.log('3. 关上冰箱门'));

// 发布
handleElephant.call();
// 1. 把冰箱门打开
// 2. 大象塞进去
// 3. 关上冰箱门

上面的例子只是最简单的一种使用方式,Tapable 的钩子可以分为两类:1. 同步钩子;2. 异步钩子。每类钩子钩子又分别具有 bail, waterfall, loop。下面就来看看这些具体的钩子。

Hook

创建钩子对象。<br/>
可以选择性的传入两个参数:1. call 函数的行参 - callArgumentNameList ;2. 钩子名称 - hookName

const callArgumentNameList = ['index'];
const hookName = 'hookName';
const hook = new SyncHook(callArgumentNameList, hookName);

创建订阅回调。<br/>
需要传入两个参数:1. tap名称 - tapName ;2. tap回调函数 - tapFn ,其中 tapFn 函数的行参同上面的 callArgumentNameList

const tapName = 'tapName';
const tapFn = (...callArgumentNameList) => console.log(index);
hook.tap(tapName, tapFn);

调用发布函数。<br/>
tapFn 函数传入参数

const callArguments = [1];
hook.call(...callArguments);

同步钩子

同步钩子处理的场景为:tap - fn 函数都是同步函数。

SyncHook 钩子

syncHook.call 函数调用时,将按照 syncHook.tap 的订阅顺序,依次执行 tap - fn 函数。

实例:

const hook = new SyncHook();

hook.tap('step1', () => '1');
hook.tap('step2', () => '2');
hook.tap('step3', () => '3');

hook.call();

hook.call 实际执行代码

(function anonymous() {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    var _fn0 = _x[0];
    _fn0();

    var _fn1 = _x[1];
    _fn1();

    var _fn2 = _x[2];
    _fn2();
})

SyncBailHook 钩子

syncBailHook.call 函数调用时,将按照 syncBailHook.tap 的订阅顺序,依次执行 tap - fn 函数。

如果某个 tap - fn 函数的返回值不为 undefined,则 call 函数返回值为该 tap - fn 函数的返回值,并且停止其他 tap - fn 函数调用。

实例:

const hook = new SyncBailHook();

hook.tap('tapA', () => {
  console.log('通过步骤1');
});
hook.tap('tapB', () => {
  console.log('通过步骤2');
  return 2;
});
hook.tap('tapC', () => {
  console.log('通过步骤3');
});

hook.call();
// 因为 tapB - fn 返回值为 2,不为 undefined 
// 所以 hook.call 函数停止执行剩余的 tap - fn,并且返回值为 2 。

// 通过步骤1

hook.call 实际执行代码

(function anonymous() {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    var _fn0 = _x[0];
    var _result0 = _fn0();

    if (_result0 !== undefined) {
    return _result0;;
    } else {
    var _fn1 = _x[1];
        var _result1 = _fn1();

        if (_result1 !== undefined) {
            return _result1;;
        } else {
            var _fn2 = _x[2];
            var _result2 = _fn2();

            if (_result2 !== undefined) {
                return _result2;;
            } else {}
        }
    }
})

SyncWaterfallHook 钩子

syncWaterfallHook.call 函数调用时,将按照 syncWaterfallHook.tap 的订阅顺序,依次执行 tap - fn 函数。

syncWaterfallHook.call 函数的返回值为该函数的第一个参数: returnValue

如果某个 tap - fn 函数的返回值不为 undefined 时,则修改 returnValue 为该函数的返回值,并且停止执行剩余的 tap - fn 函数。

实例:

const hook = new SyncWaterfallHook(['speed']);

hook.tap('tapA', (speed) => {});
hook.tap('tapB', (speed) => speed + 50);
hook.tap('tapC', (speed) => speed + 50);

hook.call(50); // 100
// 因为 tapB - fn 返回值为 100(50 + 50),不为 undefined 
// 所以 hook.call 函数停止执行剩余的 tap - fn,并且返回值为 100 。

hook.call 实际执行代码

(function anonymous(speed) {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    var _fn0 = _x[0];
    var _result0 = _fn0(speed, total);
    if (_result0 !== undefined) {
            speed = _result0;
    }

    var _fn1 = _x[1];
    var _result1 = _fn1(speed, total);
    if (_result1 !== undefined) {
            speed = _result1;
    }

    var _fn2 = _x[2];
    var _result2 = _fn2(speed, total);
    if (_result2 !== undefined) {
            speed = _result2;
    }

    return speed;
})

SyncLoopHook 钩子

syncLoopHook.call 函数调用时,将按照 syncLoopHook.tap 的订阅顺序,依次执行 tap - fn 函数。

如果某个 tap - fn 函数返回值不为 undefined 时,则停止剩余 tap - fn 函数执行,从第一个 tap - fn 函数开始重新开始一轮执行。

实例:

const hook = new SyncLoopHook();

let index = 0;

hook.tap('tapA', () => {});
hook.tap('tapB', () => {
  if (index++ < 3) return index;
});
hook.tap('tapC', () => {});

hook.call();
// 因为在 tapB - fn 函数中 index++ < 3 需要循环 3 次
// 所以 tapA - fn 函数 和 tapB - fn 函数 依次执行 3 次
// 最后 tapA - fn 函数、tapB - fn 函数、tapC - fn 函数依次执行 1 次

hook.call 实际执行代码

(function anonymous() {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList
    var _loop;

    do {
            _loop = false;

            var _fn0 = _x[0];
            var _result0 = _fn0();
            if (_result0 !== undefined) {
                    _loop = true;
            } else {
                    var _fn1 = _x[1];
                    var _result1 = _fn1();
                    if (_result1 !== undefined) {
                            _loop = true;
                    } else {
                            var _fn2 = _x[2];
                            var _result2 = _fn2();
                            if (_result2 !== undefined) {
                                    _loop = true;
                            } else {
                                    if (!_loop) {}
                            }
                    }
            }
    } while ( _loop );
})

异步钩子

异步钩子处理的场景为:tap - fn 函数都是异步函数。

异步钩子分为两大类:并行异步(parallel)、串行异步(series)。

不论并行异步还是串行异步, tap - call 的调用方式分为两种:

  1. tapAsync - callAsync

callAsync 函数参数中的最后一个参数为 callback 回调函数,该回调函数的执行表示 callAsync 异步函数执行的结束。

tapAsync - fn 函数参数中的最后一个参数为 callback 回调函数,该回调函数的执行表示 tapAsync - fn 异步函数执行的结束。

callback 函数参数中的第一个参数为 err ,当 err 为真性值时,表示有错误发生;第二个参数为 data

hook.tapAsync('tapName', (...callArgumentsNameList, callback) => {
  callback();
});

hook.callAsync(...callArgumentsNameList, callback)
  1. tapPromise - promise(call)

tapPromise - fn 函数的返回值为 promise

promise(call) 函数的返回值为 promise

hook.tapPromise('tapName', (...callArgumentsNameList) => {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 2000);
  });
});

hook.promise(...callArgumentsNameList).then(successFn, failureFn)

AsyncParallelHook 钩子

asyncParallelHook.call 函数调用时,将按照 tapAsync.tap 的订阅顺序,并行执行 tapAsync - fn 函数

如果某个 tapAsync - fn 函数的执行过程中,触发错误;则提前调用回调函数 callback(err) ,停止 callAsync 函数继续执行。

所有的 tapAsync - fn 函数都执行完毕之后,调用回调函数 callback()

实例:

const hook = new AsyncParallelHook();

hook.tapAsync('step1', (callback) => {
  setTimeout(() => {
    callback();
  }, 1000);
});
hook.tapAsync('step2', (callback) => {
  setTimeout(() => {
    callback(1);
  }, 2000);
});
hook.tapAsync('step3', (callback) => {
  setTimeout(() => {
    callback();
  }, 3000);
});

hook.callAsync((err) => {
  if (err) return console.log('有错误发生');
});
// 因为 tapAsync - step2 执行 callback 函数时第一个参数值为 1 ,触发了错误机制,提前结束 `callAsync` 的执行。
// 打印:有错误发生

hook.call 实际执行代码

(function anonymous(_callback) {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    do {
            var _counter = 3;
            var _done = (function() {
                    _callback();
            });

            if (_counter <= 0) break;
            var _fn0 = _x[0];
            _fn0((function(_err0) {
                    if (_err0) {
                            if (_counter > 0) {
                                    _callback(_err0);
                                    _counter = 0;
                            }
                    } else {
                            if (--_counter === 0) _done();
                    }
            }));

            if (_counter <= 0) break;
            var _fn1 = _x[1];
            _fn1((function(_err1) {
                    if (_err1) {
                            if (_counter > 0) {
                                    _callback(_err1);
                                    _counter = 0;
                            }
                    } else {
                            if (--_counter === 0) _done();
                    }
            }));

            if (_counter <= 0) break;
            var _fn2 = _x[2];
            _fn2((function(_err2) {
                    if (_err2) {
                            if (_counter > 0) {
                                    _callback(_err2);
                                    _counter = 0;
                            }
                    } else {
                            if (--_counter === 0) _done();
                    }
            }));
    } while ( false );
})

AsyncParallelBailHook 钩子

asyncParallelHook.call 函数调用时,将按照 tapAsync.tap 的订阅顺序,并行执行 tapAsync - fn 函数

如果某个 tapAsync - fn 函数的执行过程中,触发错误;则提前调用回调函数 callback(err) ,停止 callAsync 函数继续执行。

如果某个 tapAsync - fn 函数的执行过程中,触发熔断;则提前调用回调函数 callback(null, data) ,停止 callAsync 函数继续执行。

所有的 tapAsync - fn 函数都执行完毕之后,调用回调函数 callback()

实例:

const hook = new AsyncParallelBailHook();

hook.tapAsync('step1', (callback) => {
  setTimeout(() => {
    callback();
  }, 1000);
});
hook.tapAsync('step2', (callback) => {
  setTimeout(() => {
    callback(null, 2);
  }, 2000);
});
hook.tapAsync('step3', (callback) => {
  setTimeout(() => {
    callback();
  }, 3000);
});

hook.callAsync((err, data) => {
  if (err) return console.log('有错误发生');
  console.log(`返回值 - ${data}`);
});
// 因为 tapAsync - step2 执行 callback 函数时第二个参数值为 2 ,触发了熔断机制,提前结束 `callAsync` 的执行。
// 打印:返回值 - 2

hook.call 实际执行代码

(function anonymous(_callback) {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList
    var _results = new Array(3);

    var _checkDone = function() {
            for (var i = 0; i < _results.length; i++) {
                    var item = _results[i];
                    if (item === undefined) return false;
                    if (item.result !== undefined) {
                            _callback(null, item.result);
                            return true;
                    }
                    if (item.error) {
                            _callback(item.error);
                            return true;
                    }
            }
            return false;
    }

    do {
            var _counter = 3;
            var _done = (function() {
                    _callback();
            });

            if (_counter <= 0) break;
            var _fn0 = _x[0];
            _fn0((function(_err0, _result0) {
                    if (_err0) {
                            if (_counter > 0) {
                                    if (0 < _results.length && ((_results.length = 1), (_results[0] = {
                                            error: _err0
                                    }), _checkDone())) {
                                            _counter = 0;
                                    } else {
                                            if (--_counter === 0) _done();
                                    }
                            }
                    } else {
                            if (_counter > 0) {
                                    if (0 < _results.length && (_result0 !== undefined && (_results.length = 1), (_results[0] = {
                                            result: _result0
                                    }), _checkDone())) {
                                            _counter = 0;
                                    } else {
                                            if (--_counter === 0) _done();
                                    }
                            }
                    }
            }));

            if (_counter <= 0) break;
            if (1 >= _results.length) {
                    if (--_counter === 0) _done();
            } else {
                    var _fn1 = _x[1];
                    _fn1((function(_err1, _result1) {
                            if (_err1) {
                                    if (_counter > 0) {
                                            if (1 < _results.length && ((_results.length = 2), (_results[1] = {
                                                    error: _err1
                                            }), _checkDone())) {
                                                    _counter = 0;
                                            } else {
                                                    if (--_counter === 0) _done();
                                            }
                                    }
                            } else {
                                    if (_counter > 0) {
                                            if (1 < _results.length && (_result1 !== undefined && (_results.length = 2), (_results[1] = {
                                                    result: _result1
                                            }), _checkDone())) {
                                                    _counter = 0;
                                            } else {
                                                    if (--_counter === 0) _done();
                                            }
                                    }
                            }
                    }));
            }

            if (_counter <= 0) break;
            if (2 >= _results.length) {
                    if (--_counter === 0) _done();
            } else {
                    var _fn2 = _x[2];
                    _fn2((function(_err2, _result2) {
                            if (_err2) {
                                    if (_counter > 0) {
                                            if (2 < _results.length && ((_results.length = 3), (_results[2] = {
                                                    error: _err2
                                            }), _checkDone())) {
                                                    _counter = 0;
                                            } else {
                                                    if (--_counter === 0) _done();
                                            }
                                    }
                            } else {
                                    if (_counter > 0) {
                                            if (2 < _results.length && (_result2 !== undefined && (_results.length = 3), (_results[2] = {
                                                    result: _result2
                                            }), _checkDone())) {
                                                    _counter = 0;
                                            } else {
                                                    if (--_counter === 0) _done();
                                            }
                                    }
                            }
                    }));
            }
    } while ( false );

})

AsyncSeriesHook 钩子

asyncSeriesHook.call 函数调用时,将按照 tapAsync.tap 的订阅顺序,串行执行 tapAsync - fn 函数

如果某个 tapAsync - fn 函数的执行过程中,触发错误;则提前调用回调函数 callback(err) ,停止 callAsync 函数继续执行。

所有的 tapAsync - fn 函数都执行完毕之后,调用回调函数 callback()

实例:

const hook = new AsyncSeriesHook();

hook.tapAsync('step1', (callback) => {
  setTimeout(() => {
    console.log('step1');
    callback();
  }, 1000);
});
hook.tapAsync('step2', (callback) => {
  setTimeout(() => {
    console.log('step2');
    callback();
  }, 2000);
});
hook.tapAsync('step3', (callback) => {
  setTimeout(() => {
    console.log('step3');
    callback();
  }, 3000);
});

hook.callAsync(() => {});
// ... wait 1s ...
// step1
// ... wait 2s ...
// step2
// ... wait 3s ...
// step3

hook.call 实际执行代码

(function anonymous(_callback) {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    function _next1() {
            var _fn2 = _x[2];
            _fn2((function(_err2) {
                    if (_err2) {
                            _callback(_err2);
                    } else {
                            _callback();
                    }
            }));
    }

    function _next0() {
            var _fn1 = _x[1];
            _fn1((function(_err1) {
                    if (_err1) {
                            _callback(_err1);
                    } else {
                            _next1();
                    }
            }));
    }

    var _fn0 = _x[0];
    _fn0((function(_err0) {
            if (_err0) {
                    _callback(_err0);
            } else {
                    _next0();
            }
    }));

})

AsyncSeriesBailHook 钩子

asyncSeriesBailHook.call 函数调用时,将按照 tapAsync.tap 的订阅顺序,串行执行 tapAsync - fn 函数

如果某个 tapAsync - fn 函数的执行过程中,触发错误;则提前调用回调函数 callback(err) ,停止 callAsync 函数继续执行。

如果某个 tapAsync - fn 函数的执行过程中,触发熔断;则提前调用回调函数 callback(null, data) ,止其他 tapAsync - fn 函数调用。

所有的 tapAsync - fn 函数都执行完毕之后,调用回调函数 callback()

实例:

const hook = new AsyncSeriesBailHook();

hook.tapAsync('step1', (callback) => {
  setTimeout(() => {
    console.log('step1');
    callback();
  }, 1000);
});
hook.tapAsync('step2', (callback) => {
  setTimeout(() => {
    console.log('step2');
    callback(null, 2);
  }, 2000);
});
hook.tapAsync('step3', (callback) => {
  setTimeout(() => {
    console.log('step3');
    callback();
  }, 3000);
});

hook.callAsync((err, data) => {
  if (err) return console.log('有错误发生');
  console.log(`返回值 - ${data}`);
});
// 因为 tapAsync - step2 执行 callback 函数时第二个参数值为 2 ,触发了熔断机制,提前结束 `callAsync` 的执行。
// 打印:返回值 - 2

hook.call 实际执行代码

(function anonymous(_callback) {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    function _next1() {
            var _fn2 = _x[2];
            _fn2((function(_err2, _result2) {
                    if (_err2) {
                            _callback(_err2);
                    } else {
                            if (_result2 !== undefined) {
                                    _callback(null, _result2);
                            } else {
                                    _callback();
                            }
                    }
            }));
    }

    function _next0() {
            var _fn1 = _x[1];
            _fn1((function(_err1, _result1) {
                    if (_err1) {
                            _callback(_err1);
                    } else {
                            if (_result1 !== undefined) {
                                    _callback(null, _result1);

                            } else {
                                    _next1();
                            }
                    }
            }));
    }

    var _fn0 = _x[0];
    _fn0((function(_err0, _result0) {
            if (_err0) {
                    _callback(_err0);
            } else {
                    if (_result0 !== undefined) {
                            _callback(null, _result0);

                    } else {
                            _next0();
                    }
            }
    }));

})

AsyncSeriesLoopHook 钩子

asyncSeriesLoopHook.call 函数调用时,将按照 tapAsync.tap 的订阅顺序,串行执行 tapAsync - fn 函数

如果某个 tapAsync - fn 函数的执行过程中,触发错误;则提前调用回调函数 callback(err) ,停止 callAsync 函数继续执行。

如果某个 tapAsync - fn 函数的执行过程中,调用回调函数 callback(err, data) 中参数 data 不为 undefined ;则从第一个 tapAsync - fn 函数开始重新开始执行

所有的 tapAsync - fn 函数都执行完毕之后,调用回调函数 callback()

实例:

const hook = new AsyncSeriesLoopHook();

let index = 3;

hook.tapAsync('step1', (callback) => {
  setTimeout(() => {
    console.log('step1');
    callback();
  }, 1000);
});
hook.tapAsync('step2', (callback) => {
  setTimeout(() => {
    console.log('step2');
    callback(null,  index > 0 ? index-- : undefined);
  }, 2000);
});
hook.tapAsync('step3', (callback) => {
  setTimeout(() => {
    console.log('step3');
    callback();
  }, 3000);
});

hook.callAsync((err) => {});
// 因为 tapAsync - step2 执行的 `callback - data` 值依次为 3, 2, 1, undefined
// 所以依次执行顺序如下:
//
// step1
// step2
//
// step1
// step2
//
// step1
// step2
//
// step1
// step2
// step3

hook.call 实际执行代码

(function anonymous(_callback) {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    var _looper = (function() {
            var _loopAsync = false;
            var _loop;

            do {
                    _loop = false;

                    function _next1() {
                            var _fn2 = _x[2];
                            _fn2((function(_err2, _result2) {
                                    if (_err2) {
                                            _callback(_err2);
                                    } else {
                                            if (_result2 !== undefined) {
                                                    _loop = true;
                                                    if (_loopAsync) _looper();
                                            } else {
                                                    if (!_loop) {
                                                            _callback();
                                                    }
                                            }
                                    }
                            }));
                    }

                    function _next0() {
                            var _fn1 = _x[1];
                            _fn1((function(_err1, _result1) {
                                    if (_err1) {
                                            _callback(_err1);
                                    } else {
                                            if (_result1 !== undefined) {
                                                    _loop = true;
                                                    if (_loopAsync) _looper();
                                            } else {
                                                    _next1();
                                            }
                                    }
                            }));
                    }

                    var _fn0 = _x[0];

                    _fn0((function(_err0, _result0) {
                            if (_err0) {
                                    _callback(_err0);
                            } else {
                                    if (_result0 !== undefined) {
                                            _loop = true;
                                            if (_loopAsync) _looper();
                                    } else {
                                            _next0();
                                    }
                            }
                    }));
            } while ( _loop );

            _loopAsync = true;
    });

    _looper();

})

AsyncSeriesWaterfallHook 钩子

asyncSeriesWaterfallHook.call 函数调用时,将按照 tapAsync.tap 的订阅顺序,串行执行 tapAsync - fn 函数

如果某个 tapAsync - fn 函数的执行过程中,触发错误;则提前调用回调函数 callback(err) ,停止 callAsync 函数继续执行。

如果某个 tapAsync - fn 函数的执行过程中,调用回调函数 callback(err, data) 中参数 data 不为 undefined ;则修改 callArgumentNamelist[0]data 的值。

所有的 tapAsync - fn 函数都执行完毕之后,调用回调函数 callback(null, callArgumentNamelist[0])

实例:

const hook = new AsyncSeriesWaterfallHook(['num']);

hook.tapAsync('step1', (num, callback) => {
  setTimeout(() => {
    console.log('step1');
    callback(null, num + 1);
  }, 1000);
});
hook.tapAsync('step2', (num, callback) => {
  setTimeout(() => {
    console.log('step2');
    callback();
  }, 2000);
});
hook.tapAsync('step3', (num, callback) => {
  setTimeout(() => {
    console.log('step3');
    callback(null, num + 2);
  }, 3000);
});

hook.callAsync(1, (err, num) => {
  console.log(`返回值 - ${num}`);
});
// step1
// step2
// step3
// step3
// 返回值 - 4

hook.call 实际执行代码

(function anonymous(data, _callback) {
    "use strict";
    var _context;
    var _x = this._x; // tapFnList

    function _next1() {
            var _fn2 = _x[2];
            _fn2(data, (function(_err2, _result2) {
                    if (_err2) {
                            _callback(_err2);
                    } else {
                            if (_result2 !== undefined) {
                                    data = _result2;
                            }
                            _callback(null, data);
                    }
            }));
    }

    function _next0() {
            var _fn1 = _x[1];
            _fn1(data, (function(_err1, _result1) {
                    if (_err1) {
                            _callback(_err1);
                    } else {
                            if (_result1 !== undefined) {
                                    data = _result1;
                            }
                            _next1();
                    }
            }));
    }

    var _fn0 = _x[0];
    _fn0(data, (function(_err0, _result0) {
            if (_err0) {
                    _callback(_err0);
            } else {
                    if (_result0 !== undefined) {
                            data = _result0;
                    }
                    _next0();
            }
    }));

})

Interception

可以为每个钩子对象添加拦截器(interception):

hook.intercept({
  call(source, target, routesList) => {
        console.log("Starting to calculate routes");
    },
    register(tapInfo) => {
        // tapInfo = { type: "promise", name: "GoogleMapsPlugin", fn: ... }
        console.log(`${tapInfo.name} is doing its job`);
        return tapInfo; // may return a new tapInfo object
    }
});

当为同一个 hook 添加多个 interception 时,则按照 interception 添加顺序,依次执行。

call

(...callArgumentsNameList) => void

hook.call 函数调用前,该 call 函数将被调用。通过该函数可以访问 callArgumentsNameList

tap

(tap: Tap) => void

当某个 tap - fn 函数调用前,该 tap 函数将被调用。为该函数提供了当前 tap - fn 函数对应的 tap 对象,该对象不应该被修改。

loop

(...callArgumentsNameList) => void

当 loop 每次执行前,该 loop 函数将被调用。

register

(tap: Tap) => Tap | undefined

当每次注册 tap 前,该 register 函数将被调用。该函数输入当前 tap 对象,该对象允许修改数据。

hook.call 中 interception 实际执行代码

(function anonymous(numA, numB) {
    "use strict";
    var _context;
    var _x = this._x;
    var _taps = this.taps;
    var _interceptors = this.interceptors;
    _interceptors[0].call(numA, numB); // call
    var _loop;
    do {
            _loop = false;
            _interceptors[0].loop(numA, numB); // loop
            var _tap0 = _taps[0];
            _interceptors[0].tap(_tap0); // tap
            var _fn0 = _x[0];
            var _result0 = _fn0(numA, numB);
            if (_result0 !== undefined) {
                    _loop = true;
            } else {
                    if (!_loop) {}
            }
    } while ( _loop );

})

Context

插件和拦截器可以选择性地连接 context 对象,这是可以传递任何值给随后的插件和拦截器的对象。

context 对象初始化时为空对象 {}

如果 tap.option.contexttrue ,则该函数的第一个参数为 context 对象。

如果 intercept.contexttrue ,则 call, tap, loop 函数的第一个参数为 context 对象。

const hook = new SyncHook();

myCar.hooks.accelerate.intercept({
    context: true,
    tap: (context, tapInfo) => {
        // tapInfo = { type: "sync", name: "NoisePlugin", fn: ... }
        console.log(`${tapInfo.name} is doing it's job`);

        // `context` starts as an empty object if at least one plugin uses `context: true`.
        // If no plugins use `context: true`, then `context` is undefined.
        if (context) {
            // Arbitrary properties can be added to `context`, which plugins can then access.
            context.hasMuffler = true;
        }
    }
});

myCar.hooks.accelerate.tap({
    name: "NoisePlugin",
    context: true
}, (context, newSpeed) => {
    if (context && context.hasMuffler) {
        console.log("Silence...");
    } else {
        console.log("Vroom!");
    }
});

Steven
38 声望3 粉丝