1.异步并行钩子
//start.js(原生的异步钩子)
let { AsyncParallelHook } = require("tapable");
// 异步的钩子
// 同时发送多个请求
// 注册方法分为tap和tapAsync(同步和异步)
class Lesson {
constructor() {
this.index = 0;
this.hooks = {
arch: new AsyncParallelHook(["name"]) //此处的“name”,只是为了方便开发者阅读,语义化
};
}
tap() {
//注册监听事件
this.hooks.arch.tapAsync("aaa", (name, cb) => {
//因为是异步, 注册方法就不能使用tap了,转而使用tapAsync
setTimeout(() => {
console.log("aaa", name);
cb(); // 此处的cb是必须的,为了告诉后边的事件序列,“我完成了”
}, 1000);
});
this.hooks.arch.tapAsync("bbb", (name, cb) => {
setTimeout(() => {
console.log("bbb", name);
cb(); // 如果某个异步没有执行cb,那么永远不会执行后边的end
}, 1000);
});
}
start() {
this.hooks.arch.callAsync("lc", function() {
//这里也就不能用call了,使用callAsync
console.log("end");
});
}
}
let l = new Lesson();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
执行结果:
模拟:
//mock.js
class AsyncParalleHook {
// 异步并发钩子
constructor(args) {
//args => ["name"];
this.tasks = [];
}
tapAsync(name, task) {
this.tasks.push(task);
}
callAsync(...args) {
let finalCallback = args.pop(); // 拿出回调函数
let index = 0;
let done = () => {
index++;
if (index == this.tasks.length) { // 执行完所有函数后,执行最终的回调
finalCallback();
}
};
this.tasks.forEach(task => {
task(...args, done);
});
}
}
let hook = new AsyncParalleHook(["name"]);
let total = 0;
hook.tapAsync("aaa", function(name, cb) {
setTimeout(() => {
console.log("aaa", name);
cb();
}, 1000);
});
hook.tapAsync("bbb", function(name, cb) {
setTimeout(() => {
console.log("bbb", name);
cb();
});
});
hook.callAsync("lc", function() {
console.log("end");
});
此例类比Promise.all,所有异步成功完成之后,执行最终的回调,tapable库也提供了promise方法,如下:
//start.js
let { AsyncParallelHook } = require("tapable");
// 异步的钩子
// 同时发送多个请求
// tapable库中有三种注册方法: tap 同步注册 tapAsync(cb) tapPrimise(注册的是promise)
// 调用也有三种 call, callAsync, promise
class Lesson {
constructor() {
this.index = 0;
this.hooks = {
arch: new AsyncParallelHook(["name"]) //此处的“name”,只是为了方便开发者阅读,语义化
};
}
tap() {
//注册监听事件
this.hooks.arch.tapPromise("aaa", name => { // 注册方法改为“tapPromise”
//因为是异步, 注册方法就不能使用tap了,转而使用tapAsync
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("aaa", name);
resolve();
}, 1000);
});
});
this.hooks.arch.tapPromise("bbb", name => { // 之前的“cb”不需要了,因为在promise中有resolve来达到相同的效果
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("bbb", name);
resolve();
}, 1000);
});
});
}
start() {
this.hooks.arch.promise("lc").then(function() { // 执行回调也改为使用promise的then方法
//这里也就不能用call了,使用callAsync
console.log("end");
});
}
}
let l = new Lesson();
l.tap(); // 注册这两个事件
l.start(); // 启动钩子
模拟:
//mock.js
class AsyncParalleHook {
// 异步并发钩子
constructor(args) {
//args => ["name"];
this.tasks = [];
}
tapPromise(name, task) {
this.tasks.push(task);
}
promise(...args) {
let tasks = this.tasks.map(task => task(...args)); //将所有promise组成一个数组
return Promise.all(tasks); // 返回一个组合后的promise
}
}
let hook = new AsyncParalleHook(["name"]);
hook.tapPromise("aaa", function(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("aaa", name);
resolve();
}, 1000);
});
});
hook.tapPromise("bbb", function(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("bbb", name);
resolve();
}, 1000);
});
});
hook.promise("lc").then(function() {
console.log("end");
});
除了AsyncParalleHook,也有对应的AsyncParalleBailHook(带保险的异步并发钩子),可类比同步钩子,这里不详述,只是在以上的某个子promise中reject后,就会触发.