webpack tapable 钩子跟普通发布订阅引发的思考

613 阅读3分钟

先说对tapable的设计对我的启发

  • 应该算是使用的继承的设计模式,这次我对继承设计模式有的正儿八经的认识,实质就是抽离公共代码而已。

  • 子类调用某个方法的时候,this.xxx(),自己没有定义那个方法,会去找父类的xxx方法,进去父类的方法后, this是子类的this。这不就是抽离公共代码吗,子类相当于也拥有了父类的方法,今天才看透,晕死。

  • 提一嘴抽离公共代码,还有近几年很火的一句话,组合优于继承,组合也是抽离公共代码的一种设计。

看透了才能灵活应用。以后遇到公共代码的时候,就可以考虑考虑这两种设计模式了。

贴下demo代码

class Parent {
  constructor() {
    this.name = 'Parent';
  }

  xxx() {
    console.log(this.name);//输出Child
    this.goToChild();//输出Child,其实用记,因为childInstance调用的xxx,xxx方法里的this自然也是childInstance
  }
  
  goToChild() {
    console.log(this.name);
  }
}


class Child extends Parent{
  constructor() {
    super()
    this.name = 'Child';
  }

  goToChild() {
    console.log(this.name);
  }
}

const childInstance = new Child();
childInstance.xxx();

Tapable 跟 发布订阅 的异同

  • 原理其实都是一样的,都是存函数,然后被执行。
  • 别人帮你存函数,别人帮你调用的这类类库,典型的就是会多出一些同步异步钩子的概念出来,最近也看穿了,原因是帮你存的函数,里面可以有异步操作,比如网络请求。那么类库帮你执行的时候,就不知道你的函数,什么时候执行完了。 于是就多出了同步异步钩子的概念。
  • 异步又有两种,函数返回的promise,函数没有返回promis,但里面却有异步逻辑。为了说明这些函数执行的顺序,概念又出来了:异步并行(promise版本:原理类似promise.all,非promise版:典型的next方式),异步串行(一个一个promise的顺序执行,原理就是在单个promise[i]加个then的成功的回调,再加下一个里promise[i+1]的then的成功的回调)
  • ps一个基础只是new Funtion出来的函数this是全局的对象。

贴个promise的demo

const f1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('1');
      resolve()
    }, 1000)
  })
}

const f2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('2');
      resolve()
    }, 1000)
  })
}

const arr = [f1, f2];
const resultPromise = arr.reduce((prev, next) => prev().then(() => next()))
  • 区别:执行的时候发布订阅是遍历之前存的函数,依次执行,发布订阅有eventName。而Tapable是直接用不同的类,来区别触发函数的种类。
  • 而Tapable实现很奇怪,居然是遍历存的函数,然后拼接字符串arri,然后new Function('param1,param2', 'arr[i](param1,param2)'),有人说节约内存,性能优化。。。。感觉没优化到个啥。。这一点不是特别理解为啥他们要这么实现。。奇怪。有人知道麻烦告诉我一下。
  • 再提一嘴,vue的计算属性大家都知道吧,原生的js也支持了,而且也带缓存。常被大佬使用,作为性能优化点。

接下来就是板砖的笔记了。

  • 同步异步的视角分类:

asynctapablesync.jpg

  • 返回值分类
    Basic:执行每一个事件函数。 Bail: 就是被执行的函数如果返回值不是undefined,就会直接结束,停止执行下一个
    Waterfall:就是被执行的函数如果返回值不是undefined,会把返回值传个下一个被执行的函数,当参数
    Loop: 不停的循环执行事件函数,直到所有函数结果 result === undefined。

mytapable.jpg

  • 还有interceptor、stage、before 、hookMap interceptor就是提供在tab跟call的时候,都会被触发的函数的功能 hookMap提供假如同一种钩子,有很多个示例,分类用的。 stage对tab的钩子排序用的,排序可以决定钩子执行的顺序 before指定插入顺序