• webpack4.X之tapable实例对象AsyncParallelHook源码


    模拟手写AsyncParallelHook源码部分。

    let Hook = require('./Hook.js')
    
    class HookCodeFactory {
      args({ after, before } = {}) {
        let allArgs = this.options.args
        if (before) allArgs = [before].concat(allArgs)
        if (after) allArgs = allArgs.concat(after)
        return allArgs.join(',')  // ["name", "age"]===> name, age
      }
      head() {
        return `"use strict";var _context;var _x = this._x;`
      }
      content() {
        let code = `var _counter = ${this.options.taps.length};var _done = (function () {
          _callback();
        });`
        for (var i = 0; i < this.options.taps.length; i++) {
          code += `var _fn${i} = _x[${i}];_fn${i}(name, age, (function () {
            if (--_counter === 0) _done();
          }));`
        }
        return code
      }
      setup(instance, options) {  // 先准备后续需要使用到的数据
        this.options = options  // 这里的操作在源码中是通过 init 方法实现,而我们当前是直接挂在了 this 身上
        instance._x = options.taps.map(o => o.fn)   // this._x = [f1, f2, ....]
      }
      create() { // 核心就是创建一段可执行的代码体然后返回
        let fn
        // fn = new Function("name, age", "var _x = this._x, var _fn0 = _x[0]; _fn0(name, age);")
        fn = new Function(
          this.args({ after: '_callback' }),
          this.head() + this.content()
        )
        return fn
      }
    }
    
    let factory = new HookCodeFactory()
    
    class AsyncParallelHook extends Hook {
      constructor(args) {
        super(args)
      }
    
      compile(options) {  // {taps: [{}, {}], args: [name, age]}
        factory.setup(this, options)
        return factory.create(options)
      }
    }
    
    module.exports = AsyncParallelHook
    class Hook {
      constructor(args = []) {
        this.args = args
        this.taps = []  // 将来用于存放组装好的 {}
        this._x = undefined  // 将来在代码工厂函数中会给 _x = [f1, f2, f3....]
      }
    
      tap(options, fn) {
        if (typeof options === 'string') {
          options = { name: options }
        }
        options = Object.assign({ fn }, options)  // { fn:... name:fn1 }
    
        // 调用以下方法将组装好的 options 添加至 []
        this._insert(options)
      }
    
      tapAsync(options, fn) {
        if (typeof options === 'string') {
          options = { name: options }
        }
        options = Object.assign({ fn }, options)  // { fn:... name:fn1 }
    
        // 调用以下方法将组装好的 options 添加至 []
        this._insert(options)
      }
    
      _insert(options) {
        this.taps[this.taps.length] = options
      }
    
      call(...args) {
        // 01 创建将来要具体执行的函数代码结构
        let callFn = this._createCall()
        // 02 调用上述的函数(args传入进去)
        return callFn.apply(this, args)
      }
    
      callAsync(...args) {
        let callFn = this._createCall()
        return callFn.apply(this, args)
      }
    
      _createCall() {
        return this.compile({
          taps: this.taps,
          args: this.args
        })
      }
    }
    
    module.exports = Hook
     const SyncHook=require('./AsyncParallelHook.js')
    //const { AsyncParallelHook } =require('tapable')
    let hook=new AsyncParallelHook(["name","age"])
    
    hook.tapAsync('fn1',function(name,age,callback){
        console.log('fn1--->',name,age)
        callback()
    })
    
    hook.tapAsync('fn2',function(name,age,callback){
        console.log('fn2--->',name,age)
        callback()
    })
    
    hook.callAsync('lw',18,function(){
        console.log('end...')
    })
    ---感谢阅读,o(* ̄︶ ̄*)o开心每一天!
  • 相关阅读:
    程序调试的利器GDB
    Building a Android Development Environment
    手机的串号IMEI/ESN标示位置图解摩托罗拉官方教程
    Linux调试信息输出串口设备号的设置
    git忽略文件提交
    Spring @Transactional事务传播范围以及隔离级别
    自定义springbootstarter
    maven 命令将jar包安装到本地仓库
    oracle 常用命令
    Oracle 用户(user)和模式(schema)的区别
  • 原文地址:https://www.cnblogs.com/websiteblogs/p/14466685.html
Copyright © 2020-2023  润新知