本节代码 10_source_read/10_2_sync_hook

基本使用

同步钩子SyncHook

  1. const { SyncHook } = require('./tapable/lib/index.js');
  2. class Lesson {
  3. constructor(props) {
  4. // 创建钩子
  5. this.hooks = {
  6. arch: new SyncHook(['name']),
  7. }
  8. }
  9. tap() { // 注册监听函数
  10. // 注册了两个事件, 叫lesson1和lesson2
  11. this.hooks.arch.tap('lesson1', function(name) {
  12. console.log('lesson1', name);
  13. })
  14. this.hooks.arch.tap('lesson2', function(name) {
  15. console.log('lesson2', name);
  16. })
  17. }
  18. start() {
  19. this.hooks.arch.call('jay');
  20. }
  21. }
  22. let l = new Lesson();
  23. l.tap(); // 把lesson1和lesson2的时间分别注册到一个数组中
  24. l.start(); // 启动钩子

打印结果为:
image.png

源码实现:

  1. class SyncHook {
  2. constructor(args) {
  3. this.tasks = [];
  4. }
  5. tap(name, task) {
  6. this.tasks.push(task);
  7. }
  8. call(...args) {
  9. this.tasks.forEach(task => task(...args));
  10. }
  11. }

同步保险钩子SyncBailHook

当前一个注册函数返回值不为undefined时, 不继续向下执行

  1. const { SyncBailHook } = require('./tapable/lib/index.js');
  2. class Lesson {
  3. constructor(props) {
  4. this.hooks = {
  5. arch: new SyncBailHook(['name']),
  6. }
  7. }
  8. tap() {
  9. this.hooks.arch.tap('lesson1', function(name) {
  10. console.log('lesson1', name);
  11. return 'stop learning'; // 在这里返回一个不为undefined的值
  12. })
  13. this.hooks.arch.tap('lesson2', function(name) {
  14. console.log('lesson2', name);
  15. })
  16. }
  17. start() {
  18. this.hooks.arch.call('jay');
  19. }
  20. }
  21. let l = new Lesson();
  22. l.tap();
  23. l.start();

打印结果为:
image.png

源码实现:

  1. class SyncBailHook {
  2. constructor(args) {
  3. this.tasks = [];
  4. }
  5. tap(name, task) {
  6. this.tasks.push(task);
  7. }
  8. call(...args) {
  9. let ret; // 当前函数返回值
  10. let index = 0;
  11. do {
  12. ret = this.tasks[index++](...args);
  13. } while (ret === undefined && this.tasks.length > index);
  14. }
  15. }

同步流式钩子SyncWaterfallHook

可以接收到上一个函数的返回结果作为参数传入到下一个函数中去

  1. const { SyncWaterfallHook } = require('./tapable/lib/index.js');
  2. class Lesson {
  3. constructor(props) {
  4. // 创建钩子
  5. this.hooks = {
  6. arch: new SyncWaterfallHook(['name']),
  7. }
  8. }
  9. tap() {
  10. this.hooks.arch.tap('lesson1', function(name) {
  11. console.log('lesson1', name);
  12. return 'lesson1 result'; // 返回lesson1结果
  13. })
  14. this.hooks.arch.tap('lesson2', function(data) { // data作为传参接受lesson1结果
  15. console.log('lesson2', data);
  16. })
  17. }
  18. start() {
  19. this.hooks.arch.call('jay');
  20. }
  21. }
  22. let l = new Lesson();
  23. l.tap();
  24. l.start();

image.png

源码实现:

  1. class SyncWaterfallHook {
  2. constructor(args) {
  3. this.tasks = [];
  4. }
  5. tap(name, task) {
  6. this.tasks.push(task);
  7. }
  8. call(...args) {
  9. const [first, ...other] = this.tasks;
  10. const ret = first(...args);
  11. other.reduce((prev, next) => next(prev), ret);
  12. }
  13. }
  14. const hook = new SyncWaterfallHook(['name']);
  15. hook.tap('lesson1', function (name) {
  16. console.log('lesson1', name);
  17. return 'lesson1 result'
  18. })
  19. hook.tap('lesson2', function (data) {
  20. console.log('lesson2', data);
  21. })
  22. hook.call('jay');

同步循环钩子SyncLoopHook

可以手动指定上一个函数的执行次数, 直到上个函数返回undefined才执行下一个函数
这个方法在webpack中并没有用到

  1. const { SyncLoopHook } = require('./tapable/lib/index.js');
  2. class Lesson {
  3. constructor(props) {
  4. // 创建钩子
  5. this.hooks = {
  6. arch: new SyncLoopHook(['name']),
  7. }
  8. this.counter = 0;
  9. }
  10. tap() {
  11. this.hooks.arch.tap('lesson1', name => {
  12. console.log('lesson1', name);
  13. return ++this.counter === 3 ? undefined : 'continue'; // 循环3次lesson1
  14. })
  15. this.hooks.arch.tap('lesson2', data => {
  16. console.log('lesson2', data);
  17. })
  18. }
  19. start() {
  20. this.hooks.arch.call('jay');
  21. }
  22. }
  23. let l = new Lesson();
  24. l.tap();
  25. l.start();

image.png

源码实现:

  1. class SyncLoopHook {
  2. constructor(args) {
  3. this.tasks = [];
  4. }
  5. tap(name, task) {
  6. this.tasks.push(task);
  7. }
  8. call(...args) {
  9. this.tasks.forEach(task => {
  10. let ret;
  11. do {
  12. ret = task(...args);
  13. } while (ret !== undefined);
  14. });
  15. }
  16. }
  17. let counter = 0;
  18. const hook = new SyncLoopHook(["name"]);
  19. hook.tap("lesson1", function(name) {
  20. console.log("lesson1", name);
  21. return ++counter === 3 ? undefined : "continue";
  22. });
  23. hook.tap("lesson2", function(data) {
  24. console.log("lesson2", data);
  25. });
  26. hook.call("jay");