这一节的代码位于 10_source_read/10_3_async_hook
异步并行钩子AsyncParallelHook
所有函数同时执行, 执行完成后才执行最后的回调
const { AsyncParallelHook } = require("./tapable/lib/index.js");class Lesson {constructor(props) {// 创建钩子this.hooks = {arch: new AsyncParallelHook(["name"])};this.counter = 0;}tap() {// 使用tapAsync注册异步事件this.hooks.arch.tapAsync("lesson1", (name, cb) => {setTimeout(() => {console.log("lesson1", name);cb(); // cb相当于计数器, 当每个cb都执行完, 才会执行真正的回调函数}, 1000);});this.hooks.arch.tapAsync("lesson2", (data, cb) => {setTimeout(() => {console.log("lesson2", data);cb();}, 2000);});}start() {this.hooks.arch.callAsync("jay", function() {console.log('end');});}}let l = new Lesson();l.tap();l.start(); // 启动钩子
执行结果: 一秒后打印lesson1 jay, 再过一秒后打印lesson2 jay和end
源码实现:
class AsyncParallelHook {constructor(args) {this.tasks = [];}tapAsync(name, task) {this.tasks.push(task);}callAsync(...args) {const finalCallback = args.pop(); // 提取出最终的回调函数let counter = 0; // 用于计数异步函数完成时的回调, 每次异步函数完成, 触发回调, 计数+1// 当所有异步函数完成, 计数等于传入的异步任务数, 执行最终回调函数let done = () => {counter++;if(counter === this.tasks.length) {finalCallback();}}this.tasks.forEach(task => {task(...args, done);})}}// 测试代码const hook = new AsyncParallelHook(["name"]);hook.tapAsync("lesson1", function(name, cb) {setTimeout(() => {console.log("lesson1", name);cb();}, 1000)});hook.tapAsync("lesson2", function(name, cb) {setTimeout(() => {console.log("lesson2", name);cb();}, 2000)});hook.callAsync("jay", function () {console.log('end');});
异步并行钩子AsyncParallelHook(Promise)
和上面才去回调判断异步执行完成不同,直接使用promise对象来实现
const { AsyncParallelHook } = require("./tapable/lib/index.js");class Lesson {constructor(props) {// 创建钩子this.hooks = {arch: new AsyncParallelHook(["name"])};}tap() {// 使用tapPromise注册异步事件this.hooks.arch.tapPromise("lesson1", name => new Promise((resolve, reject) => {setTimeout(() => {console.log("lesson1", name);resolve(); // 取消cb回调, 使用resolve来确认异步执行完成}, 1000);}));this.hooks.arch.tapPromise("lesson2", data => new Promise((resolve, reject) => {setTimeout(() => {console.log("lesson2", data);resolve();}, 2000);}));}start() {this.hooks.arch.promise("jay").then(function() {console.log("end");});}}let l = new Lesson();l.tap();l.start(); // 启动钩子
执行结果同上, 一秒后打印lesson1 jay, 再过一秒后打印lesson2 jay和end
源码实现:
class AsyncParallelHookPromise {constructor(args) {this.tasks = [];}tapPromise(name, task) {this.tasks.push(task);}promise(...args) {let tasks = this.tasks.map(task => task(...args));return Promise.all(tasks);}}
异步串行钩子AsyncSeriesHook
上一个异步函数执行完后, 把结果传入到下一个异步函数
const { AsyncSeriesHook } = require("./tapable/lib/index.js");class Lesson {constructor(props) {// 创建钩子this.hooks = {arch: new AsyncSeriesHook(["name"])};}tap() {this.hooks.arch.tapAsync("lesson1", (name, cb) => {setTimeout(() => {console.log("lesson1", name);cb();}, 1000);});this.hooks.arch.tapAsync("lesson2", (data, cb) => {setTimeout(() => {console.log("lesson2", data);cb();}, 2000);});}start() {this.hooks.arch.callAsync("jay", function() {console.log("end");});}}let l = new Lesson();l.tap();l.start(); // 启动钩子
执行结果: 过一秒出现lesson1, 再过两秒出现lesson2
源码实现:
class AsyncSeriesHook {
constructor(args) {
this.tasks = [];
}
tapAsync(name, task) {
this.tasks.push(task);
}
callAsync(...args) {
const finalCallback = args.pop();
let counter = 0; // 判断执行了多少个异步回调
let next = () => {
if(this.tasks.length === counter) return finalCallback(); // 当执行的异步回调函数和任务数相同时, 执行最后的回调函数
let task = this.tasks[counter++];
task(...args, next);
}
next();
}
}
异步串行钩子AsyncSeriesHook(Promise)
同并行的promise写法, 串行也有对应的promise模式
const { AsyncSeriesHook } = require("./tapable/lib/index.js");
class Lesson {
constructor(props) {
// 创建钩子
this.hooks = {
arch: new AsyncSeriesHook(["name"])
};
}
tap() {
this.hooks.arch.tapPromise("lesson1", name => new Promise((resolve, reject) => {
setTimeout(() => {
console.log("lesson1", name);
resolve();
}, 1000);
}));
this.hooks.arch.tapPromise("lesson2", data => new Promise((resolve, reject) => {
setTimeout(() => {
console.log("lesson2", data);
resolve();
}, 2000);
}));
}
start() {
this.hooks.arch.promise("jay").then(function() {
console.log("end");
});
}
}
let l = new Lesson();
l.tap();
l.start(); // 启动钩子
执行结果: 过一秒出现lesson1, 再过两秒出现lesson2
源码实现:
class AsyncSeriesHookPromise {
constructor(args) {
this.tasks = [];
}
tapPromise(name, task) {
this.tasks.push(task);
}
promise(...args) {
const [first, ...other] = this.tasks;
return other.reduce((prev, next) => prev.then(() => next(...args)), first(...args));
}
}
异步串行瀑布流钩子AsyncSeriesWaterfallHook
通过在前一个异步任务中的回调函数中传入结果, 把这个结果传入到下一个异步任务中去, 可以在下一个异步任务中获取结果, 回调函数参数有两个, 第一个为null, 第二个为结果时, 正常的把结果向下一个异步任务传递, 第一个参数不为null时, 表示终结此次瀑布流操作
const { AsyncSeriesWaterfallHook } = require("./tapable/lib/index.js");
class Lesson {
constructor(props) {
// 创建钩子
this.hooks = {
arch: new AsyncSeriesWaterfallHook(["name"])
};
}
tap() {
this.hooks.arch.tapAsync("lesson1", (name, cb) => {
setTimeout(() => {
console.log("lesson1", name);
// 此时表示把lesson1的结果传到lesson2中
cb(null, 'lesson1 result');
// cb('error', 'error result');
// 如果cb是如此传递信息, 则中断瀑布流
}, 1000);
});
this.hooks.arch.tapAsync("lesson2", (data, cb) => {
setTimeout(() => {
console.log("lesson2", data);
cb();
}, 2000);
});
}
start() {
this.hooks.arch.callAsync("jay", function() {
console.log('end');
});
}
}
let l = new Lesson();
l.tap();
l.start(); // 启动钩子
打印结果为:
源码实现:
class AsyncSeriesWaterfallHook {
constructor(args) {
this.tasks = [];
}
tapAsync(name, task) {
this.tasks.push(task);
}
callAsync(...args) {
const finalCallback = args.pop();
let counter = 0;
const next = (err, data) => {
let task = this.tasks[counter];
if (!task) return finalCallback();
if (counter === 0) {
task(...args, next);
} else {
task(data, next);
}
counter++;
};
next();
}
}
异步串行瀑布流钩子AsyncSeriesWaterfallHook(Promise)
瀑布流的promise版
const { AsyncSeriesWaterfallHook } = require("./tapable/lib/index.js");
class Lesson {
constructor(props) {
// 创建钩子
this.hooks = {
arch: new AsyncSeriesWaterfallHook(["name"])
};
}
tap() {
this.hooks.arch.tapPromise("lesson1", name => new Promise((resolve, reject) => {
setTimeout(() => {
console.log("lesson1", name);
resolve("lesson1 result"); // 返回结果
}, 1000);
}));
this.hooks.arch.tapPromise("lesson2", data => new Promise((resolve, reject) => {
setTimeout(() => {
console.log("lesson2", data);
resolve();
}, 2000);
}));
}
start() {
this.hooks.arch.promise("jay").then(function() {
console.log('end');
});
}
}
let l = new Lesson();
l.tap();
l.start(); // 启动钩子
执行结果:
源码实现:
class AsyncSeriesWaterfallHookPromise {
constructor(args) {
this.tasks = [];
}
tapPromise(name, task) {
this.tasks.push(task);
}
promise(...args) {
const [first, ...other] = this.tasks;
return other.reduce((prev, next) => prev.then(data => next(data)), first(...args));
}
}
