Appearance
SyncWaterfallHook
同步瀑布流执行
特点
- 串行
- 上一个事件处理函数的返回值作为参数传递给下一个事件处理函数
源码分析
我们看 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; }
去覆盖传给下一个事件流的第一个参数