webpack 4.0 AsyncHook(异步钩子)

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(); // 启动钩子

执行结果:

822.png

模拟:

//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后,就会触发.

你可能感兴趣的:(webpack 4.0 AsyncHook(异步钩子))