美文网首页
手写SyncHook&AsyncParallelHook

手写SyncHook&AsyncParallelHook

作者: JerrySi | 来源:发表于2022-01-26 20:30 被阅读0次
    1. Hook 基类,负责通用方法实现
    class Hook {
        constructor(args = []) {
            this.args = args
            // 用于存储所有的tap对象
            this.taps = []
            // 用于存储所有的tap里面的fn
            // 代码工厂负责赋值
            this._x = undefined
        }
    
        tap(option, fn) {
            if (typeof option === 'string') {
                option = {name: option}
            }
    
            // 合并
            option = Object.assign({fn}, option)// { fn:... name:fn1 }
    
            // 调用以下方法将组装好的 options 添加至 []
            this._insert(option)
        }
    
        call(...args) {
            // 01 创建将来要具体执行的函数代码结构
            let callFn = this._createCall()
            // 02 调用上述的函数(args传入进去)
            return callFn.apply(this, args)
        }
    
        _createCall() {
            return this.compile({
                taps: this.taps,
                args: this.args
            })
        }
    
        _insert(options) {
            this.taps[this.taps.length] = options
          }
    }
    
    module.exports = Hook
    
    1. HookCodeFactory & SyncHook
      HookCodeFactory 代码构建
      SyncHook 子类
    let Hook = require("./Hook.js")
    
    class HookCodeFactory {
        args() {
            return this.options.args.join(',')
        }
        head() {
            return 'var _x = this._x;'
        }
        content() {
            let code = ''
            for (let i = 0; i < this.options.taps.length; i++) {
                code += `var _fn${i} = _x[${i}]; _fn${i}(${this.args()});`
            }
            return code;
        }
    
        init(options) {
            this.options = options  
        }
    
        // instance就是Hook
        // options: {taps: [{}, {}], args: [name, age]}
        setup(instance, options) {
            // this._x = [f1, f2, ....]
            instance._x = options.taps.map(o => o.fn)   
        }
        // 核心就是创建一段可执行的代码体然后返回
        create(options) { 
            this.init(options)
    
            let fn
            // fn = new Function("name, age", "var _x = this._x, var _fn0 = _x[0]; _fn0(name, age);")
            fn = new Function(
              this.args(),
              this.head() + this.content()
            )
            return fn
          }
    }
    
    let factory = new HookCodeFactory()
    
    class SyncHook extends Hook {
        constructor(args) {
            super(args)
        }
    
        // {taps: [{}, {}], args: [name, age]}
        compile(options) {  
            factory.setup(this, options)
            return factory.create(options)
          }
    }
    
    module.exports = SyncHook
    
    1. HookCodeFactory & AsyncParallelHook
      AsyncParallelHook主要是要处理下callback
    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
    
    

    相关文章

      网友评论

          本文标题:手写SyncHook&AsyncParallelHook

          本文链接:https://www.haomeiwen.com/subject/zqbghrtx.html