Skip to content

SyncWaterfallHook

同步瀑布流执行

特点

  1. 串行
  2. 上一个事件处理函数的返回值作为参数传递给下一个事件处理函数

源码分析

我们看 SyncWaterfallHook 的 content

js
return this.callTapsSeries({
  onError: (i, err) => onError(err),
  onResult: (i, result, next) => {
    let code = ""
    code += `if(${result} !== undefined) {\n`
    code += `${this._args[0]} = ${result};\n`
    code += `}\n`
    code += next()
    return code
  },
  onDone: () => onResult(this._args[0]),
  rethrowIfPossible,
})

其定义了 onResult 就会在 if(onResult) 生成 var _result0 = _fn0(name, age); 然后执行 onResult()

js
// 对于那些依赖上一个事件流的返回值的钩子函数,其不会只是简单的 _fn0(xxx, arg2);而是 var _result0 = _fn0(xxx, arg2);
if (onResult) {
  code += `var _result${tapIndex} = _fn${tapIndex}(${this.args({
    before: tap.context ? "_context" : undefined,
  })});\n`
} else {
  code += `_fn${tapIndex}(${this.args({
    before: tap.context ? "_context" : undefined,
  })});\n`
}
if (!rethrowIfPossible) {
  code += "} catch(_err) {\n"
  code += `_hasError${tapIndex} = true;\n`
  code += onError("_err")
  code += "}\n"
  code += `if(!_hasError${tapIndex}) {\n`
}
// 然后在最后调用各自定义的 onResult() 去处理返回值
if (onResult) {
  code += onResult(`_result${tapIndex}`)
}
if (onDone) {
  code += onDone()
}

其原理就是在每一个事件流的最后添加一个

js
if (_result0 !== undefined) {
  name = _result0
}

去修改传给下一个事件流的第一个参数。

生成的全部代码是

js
new Function(
  "name,age",
  `
'use strict';
var _context;
var _x = this._x;
var _taps = this.taps;
var _interceptors = this.interceptors;
_interceptors[0].call(name, age);
var _tap0 = _taps[0];
_interceptors[0].tap(_tap0);
var _fn0 = _x[0];
var _result0 = _fn0(name, age);
if (_result0 !== undefined) {
	name = _result0;
}
var _tap1 = _taps[1];
_interceptors[0].tap(_tap1);
var _fn1 = _x[1];
var _result1 = _fn1(name, age);
if (_result1 !== undefined) {
	name = _result1;
}
`
)

// 可以看出相对于 syncHook 其实现串行的方式就是
// var _result1 = _fn1(name, age);
// if(_result1 !== undefined) {
// 	name = _result1;
// }
// 将不为空的回调返回值去覆盖第一个参数

从上面可以看出,tapable 实现串行(上一个事件处理函数的返回值作为参数传递给下一个事件处理函数)的方式是 var _result1 = _fn1(name, age); 获取上一个的返回值,然后if(_result1 !== undefined) { name = _result1; } 去覆盖传给下一个事件流的第一个参数

上次更新: