Appearance
AsyncSeriesBailHook
AsyncSeriesBailHook 为异步串行执行的。和我们上面的 AsyncParallelHook 一样,通过使用 tapAsync 注册事件,通过 callAsync 触发事件,也可以通过 tapPromise 注册事件,使用 promise 来触发。
其与其他的 AsyncSeries[XX]hook 不同的地方在于跟 syncHook 系列的命名一样 这个也是如果事件处理函数执行时有一个返回值不为空(即返回值为 undefined),则跳过剩下未执行的事件处理函数(如类的名字,意义在于保险)
例子
js
const { AsyncSeriesBailHook } = require('tapable');
// 创建一个同步事件流实例对象
const h1 = new AsyncSeriesBailHook(['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, true);
}, 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
发现其秒数都是间隔 2 秒,那么说明所有的事件流是串行执行的,下一个事件流需要等待上一个事件流的完成才会执行。
其中在 A 中 done(undefined , 'gzhA');
所以下面的就不执行了,其原理跟 SyncbailHook 是一样的, 如果如果事件处理函数执行时有一个返回值不为空(即返回值为 undefined),则跳过剩下未执行的事件处理函数
原理
this.content()
js
class AsyncSeriesBailHookCodeFactory extends HookCodeFactory {
content({ onError, onResult, onDone }) {
return this.callTapsSeries({
onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true),
onResult: (i, result, next) => `if(${result} !== undefined) {\n${onResult(result)};\n} else {\n${next()}}\n`,
onDone,
});
}
}
发现其直接通过 this.callTapsSeries()去生成可以执行的代码的
从上面的流程可以看出其整体的过程是其实跟 asyncSeriesHook 是一样的,只是在else{}
的加入了
js
(_err0, _result0) => {
if (_err0) {
_callback(_err0);
} else {
} else {
if (_result0 !== undefined) {
_callback(null, _result0);
} else {
// xxxxxxxxxxxxxxxxxxx
}
}
如果传入的不为 undefined 的参数,那么就会直接 callback
全部伪代码
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) {
_callback(null, _result0);
} else {
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) {
_callback(null, _result1);
} else {
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) {
_callback(null, _result2);
} else {
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) {
_callback(null, _result3);
} else {
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) {
_callback(null, _result4);
} else {
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) {
_callback(null, _result5);
} else {
_callback();
}
}
});
}
}
});
}
}
});
}
}
});
}
}
});
}
}
});