Skip to content

AsyncSeriesWaterfallHook

AsyncSeriesWaterfallHook 为异步串行执行的。和我们上面的 AsyncParallelHook 一样,通过使用 tapAsync 注册事件,通过 callAsync 触发事件,也可以通过 tapPromise 注册事件,使用 promise 来触发。

其与其他的 AsyncSeries[XX]hook 不同的地方在于跟 syncHook 系列的命名一样 这个也是上一个事件处理函数的返回值作为参数传递给下一个事件处理函数

例子

js
const { AsyncSeriesWaterfallHook } = require('tapable');

// 创建一个同步事件流实例对象
const h1 = new AsyncSeriesWaterfallHook(['xxx', 'arg2']);

h1.intercept({
	call: (source, target, routesList) => {
		console.log('Starting to h1 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
	},
	tap: tap => {
		console.log(tap, '444444');
	},
});

// 添加同步事件A
h1.tapAsync('A', (name, age, done) => {
	setTimeout(() => {
		console.log('A', name, age, new Date().getSeconds());
		done(undefined, 'gzhA');
	}, 2000);
});

// 添加同步事件B
h1.tapAsync('B', (name, age, done) => {
	setTimeout(() => {
		console.log('B', name, age, new Date().getSeconds());
		done();
	}, 2000);
});

// 添加同步事件C
h1.tapAsync('C', (name, age, done) => {
	setTimeout(() => {
		console.log('C', name, age, new Date().getSeconds());
		done();
	}, 2000);
});
// 添加同步事件F
h1.tapAsync(
	{
		name: 'F',
		before: 'D',
	},
	(name, age, done) => {
		setTimeout(() => {
			console.log('F', name, age, new Date().getSeconds());
			done();
		}, 2000);
	}
);
// 添加同步事件E
h1.tapAsync(
	{
		name: 'E',
		before: 'C',
	},
	(name, age, done) => {
		setTimeout(() => {
			console.log('E', name, age, new Date().getSeconds());
			done();
		}, 2000);
	}
);
// 添加同步事件D
h1.tapAsync('D', (name, age, done) => {
	setTimeout(() => {
		console.log('D', name, age, new Date().getSeconds());
		done();
	}, 2000);
});

// 执行这个事件流
h1.callAsync('立早', 20, () => {
	console.log('函数执行完毕');
});

结果为

[HMR] Waiting for update signal from WDS...
A is doing its job
B is doing its job
C is doing its job
F is doing its job
E is doing its job
D is doing its job

Starting to h1 routes
 {type: "async", fn: ƒ, name: "F", before: "D"} "444444"
 {type: "async", fn: ƒ, name: "A"} "444444"
 {type: "async", fn: ƒ, name: "B"} "444444"
 {type: "async", fn: ƒ, name: "E", before: "C"} "444444"
 {type: "async", fn: ƒ, name: "C"} "444444"
 {type: "async", fn: ƒ, name: "D"} "444444"

[WDS] Hot Module Replacement enabled.

F 立早 20 50
{type: "async", fn: ƒ, name: "A"} "444444"
A 立早 20 52
{type: "async", fn: ƒ, name: "B"} "444444"
B gzhA 20 54
{type: "async", fn: ƒ, name: "E", before: "C"} "444444"
E gzhA 20 56
{type: "async", fn: ƒ, name: "C"} "444444"
C gzhA 20 58
{type: "async", fn: ƒ, name: "D"} "444444"
D gzhA 20 0

发现其秒数都是间隔 2 秒,那么说明所有的事件流是串行执行的,下一个事件流需要等待上一个事件流的完成才会执行。

其中在 A 中 done(undefined , 'gzhA'); 修改了传递给下一个事件流的第一个参数

原理

this.content()

js
class AsyncSeriesWaterfallHookCodeFactory extends HookCodeFactory {
	content({ onError, onResult, onDone }) {
		return this.callTapsSeries({
			onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true),
			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]),
		});
	}
}

发现其直接通过 this.callTapsSeries()去生成可以执行的代码的,但是其与 syncHook 等不同的地方在于其 option.type === 'async'

那么这时候我们就可以看到 callTap 的 async 部分了

从上面的流程可以看出其整体的过程是其实跟 asyncSeriesHook 是一样的,只是在else{}的加入了

js
} else {
		if (_result0 !== undefined) {
			xxx = _result0;
    }
    // xxxxxxxxxxxxxxxxxxx
}

在下一个事件流执行的时候将第一个参数修改了

全部伪代码
js
var _tap0 = _taps[0];
_interceptors[0].tap(_tap0);
var _fn0 = _x[0];
_fn0(xxx, arg2, (_err0, _result0) => {
	if (_err0) {
		_callback(_err0);
	} else {
		if (_result0 !== undefined) {
			xxx = _result0;
		}
		var _tap1 = _taps[1];
		_interceptors[0].tap(_tap1);
		var _fn1 = _x[1];
		_fn1(xxx, arg2, (_err1, _result1) => {
			if (_err1) {
				_callback(_err1);
			} else {
				if (_result1 !== undefined) {
					xxx = _result1;
				}
				var _tap2 = _taps[2];
				_interceptors[0].tap(_tap2);
				var _fn2 = _x[2];
				_fn2(xxx, arg2, (_err2, _result2) => {
					if (_err2) {
						_callback(_err2);
					} else {
						if (_result2 !== undefined) {
							xxx = _result2;
						}
						var _tap3 = _taps[3];
						_interceptors[0].tap(_tap3);
						var _fn3 = _x[3];
						_fn3(xxx, arg2, (_err3, _result3) => {
							if (_err3) {
								_callback(_err3);
							} else {
								if (_result3 !== undefined) {
									xxx = _result3;
								}
								var _tap4 = _taps[4];
								_interceptors[0].tap(_tap4);
								var _fn4 = _x[4];
								_fn4(xxx, arg2, (_err4, _result4) => {
									if (_err4) {
										_callback(_err4);
									} else {
										if (_result4 !== undefined) {
											xxx = _result4;
										}
										var _tap5 = _taps[5];
										_interceptors[0].tap(_tap5);
										var _fn5 = _x[5];
										_fn5(xxx, arg2, (_err5, _result5) => {
											if (_err5) {
												_callback(_err5);
											} else {
												if (_result5 !== undefined) {
													xxx = _result5;
												}
												_callback(null, xxx);
											}
										});
									}
								});
							}
						});
					}
				});
			}
		});
	}
});

上次更新: