tapable 原理解析 2

tapable 原理解析 2

本文查看tapable中 sync 方式的方法运行的方式以及context和intercept的运行逻辑

1. SyncHook

执行下面的代码

const { SyncHook } = require('../lib/index')

const hook = new SyncHook(["arg1", "arg2"]);

hook.tap('1', function (arg1, arg2) {
  console.log('1', arg1, arg2)
})
hook.tap('2', function (arg1, arg2) {
  console.log('2', arg1, arg2)
})
hook.tap('3', function (arg1, arg2) {
  console.log('3', arg1, arg2)
})
hook.call('a1', 'a2', 'a3')

得到的函数和输出结果:

function anonymous(arg1, arg2) {
  "use strict";
  var _context;
  var _x = this._x; 
  var _fn0 = _x[0];
  _fn0(arg1, arg2);
  var _fn1 = _x[1];
  _fn1(arg1, arg2);
  var _fn2 = _x[2];
  _fn2(arg1, arg2);
}
/* 输出

1 a1 a2
2 a1 a2
3 a1 a2
*/

可以看到SyncHook的调用很简单,顺序同步执行不关心结果。

2. SyncBailHook

执行代码

const hook = new SyncBailHook(["arg1", "arg2"]); 
// ...
// 与前面一样

得到的函数和输出结果:

function anonymous(arg1, arg2) {
  "use strict";
  var _context;
  var _x = this._x;
  var _fn0 = _x[0];
  var _result0 = _fn0(arg1, arg2);
  if (_result0 !== undefined) {
    return _result0;
    ;
  } else {
    var _fn1 = _x[1];
    var _result1 = _fn1(arg1, arg2);
    if (_result1 !== undefined) {
      return _result1;
      ;
    } else {
      var _fn2 = _x[2];
      var _result2 = _fn2(arg1, arg2);
      if (_result2 !== undefined) {
        return _result2;
        ;
      } else {
      }
    }
  }
}

可以看到SyncBailHook的调用也很简单,只要执行过程中一个订阅函数返回值不为undefined就会暂停后续订阅的执行

3. SyncWaterfallHook

const hook = new SyncWaterfallHook(["arg1", "arg2"]); 
// ...
// 与前面一样

得到的函数和输出结果:

function anonymous(arg1, arg2) {
  "use strict";
  var _context;
  var _x = this._x;
  var _fn0 = _x[0];
  var _result0 = _fn0(arg1, arg2);
  if (_result0 !== undefined) {
    arg1 = _result0;
  }
  var _fn1 = _x[1];
  var _result1 = _fn1(arg1, arg2);
  if (_result1 !== undefined) {
    arg1 = _result1;
  }
  var _fn2 = _x[2];
  var _result2 = _fn2(arg1, arg2);
  if (_result2 !== undefined) {
    arg1 = _result2;
  }
  return arg1;

}

可以看到SyncWaterfallHook的调用也很简单,执行过程中会使用上一个订阅的返回值。

4. SyncLoopHook

const hook = new SyncLoopHook(["arg1", "arg2"]); 
// ...
// 与前面一样

得到的函数和输出结果:

function anonymous(arg1, arg2) {
  "use strict";
  var _context;
  var _x = this._x;
  var _loop;
  do {
    _loop = false;
    var _fn0 = _x[0];
    var _result0 = _fn0(arg1, arg2);
    if (_result0 !== undefined) {
      _loop = true;
    } else {
      var _fn1 = _x[1];
      var _result1 = _fn1(arg1, arg2);
      if (_result1 !== undefined) {
        _loop = true;
      } else {
        var _fn2 = _x[2];
        var _result2 = _fn2(arg1, arg2);
        if (_result2 !== undefined) {
          _loop = true;
        } else {
          if (!_loop) {
          }
        }
      }
    }
  } while (_loop);

}

可以看到SyncLoopHook的调用也很简单,只要执行过程中一个订阅函数返回值不为undefined,函数就会重新从第一个订阅函数再次按顺序执行

5. SyncHook 结合context

执行代码


const hook = new SyncLoopHook(["arg1", "arg2"]);


hook.tap('1', function (arg1, arg2) {
  console.log('1', arg1, arg2)
})

hook.tap('2', function (arg1, arg2) {
  console.log('2', arg1, arg2)
})

hook.tap('3', function (arg1, arg2) {
  console.log('3', arg1, arg2)
})
hook.intercept({
  call: (source, target, routesList) => {
    console.log("intercept call");
  },
  loop: (source, target, routesList) => {
    console.log("intercept loop");
  },
  tap: (source, target, routesList) => {
    console.log("intercept tap");
  },
  register: (tapInfo) => {
    console.log("intercept register");
    console.log(`${tapInfo.name} is doing its job`);
    return tapInfo; // may return a new tapInfo object
  }
})

hook.call('a1', 'a2', 'a3')

得到的函数和输出结果:

function anonymous(arg1, arg2) {
  "use strict";
  var _context = {};
  var _x = this._x;
  var _fn0 = _x[0];
  _fn0(_context, arg1, arg2);
  var _fn1 = _x[1];
  _fn1(arg1, arg2);
  var _fn2 = _x[2];
  _fn2(_context, arg1, arg2);

}

/* 输出

1 a1 a2
2 a1 a2
okk
3 a1 a2
*/

当在订阅时开启context选项,在调用过程中就会给调用方法第一个参数传递context对象。可以在执行过程中在不同的订阅函数中传递数据

6. SyncHook 结合intercept

intercept代码执行过程

// intercept方法
{
        this.interceptors.push (interceptor));
        if (interceptor.register) {
            for (let i = 0; i < this.taps.length; i++) {
                this.taps[i] = interceptor.register(this.taps[i]);
            }
        }
}
// 同时在tap时调用 interceptor.register,
{
        for (const interceptor of this.interceptors) {
            if (interceptor.register) {
                const newOptions = interceptor.register(options);
                if (newOptions !== undefined) {
                    options = newOptions;
                }
            }
        }
}

可以看出register方法使用来接收原来的对订阅的函数进行拦截处理。

执行代码


const { SyncHook } = require('../lib/index')


const hook = new SyncHook(["arg1", "arg2"]);

hook.tap('1', function (arg1, arg2) {
  console.log('1', arg1, arg2)
})

hook.tap('2', function (arg1, arg2) {
  console.log('2', arg1, arg2)
})

hook.tap('3', function (arg1, arg2) {
  console.log('3', arg1, arg2)
})
hook.intercept({
  call: (source, target, routesList) => {
    console.log("intercept call");
  },
  tap: (source, target, routesList) => {
    console.log("intercept tap");
  },
  register: (tapInfo) => {
    console.log("intercept register");
    console.log(`${tapInfo.name} is doing its job`);
    return tapInfo; // may return a new tapInfo object
  }
})

hook.call('a1', 'a2', 'a3')

得到的函数和输出结果:


function anonymous(arg1, arg2) {
  "use strict";
  var _context;
  var _x = this._x;
  var _taps = this.taps;
  var _interceptors = this.interceptors;
  _interceptors[0].call(arg1, arg2);
  var _loop;
  do {
    _loop = false;
    _interceptors[0].loop(arg1, arg2);
    var _tap0 = _taps[0];
    _interceptors[0].tap(_tap0);
    var _fn0 = _x[0];
    var _result0 = _fn0(arg1, arg2);
    if (_result0 !== undefined) {
      _loop = true;
    } else {
      var _tap1 = _taps[1];
      _interceptors[0].tap(_tap1);
      var _fn1 = _x[1];
      var _result1 = _fn1(arg1, arg2);
      if (_result1 !== undefined) {
        _loop = true;
      } else {
        var _tap2 = _taps[2];
        _interceptors[0].tap(_tap2);
        var _fn2 = _x[2];
        var _result2 = _fn2(arg1, arg2);
        if (_result2 !== undefined) {
          _loop = true;
        } else {
          if (!_loop) {
          }
        }
      }
    }
  } while (_loop);

}
/* 输出: 
intercept register
1 is doing its job
intercept register
2 is doing its job
intercept register
3 is doing its job
current fn content: 

intercept call
intercept loop
intercept tap
1 a1 a2
intercept tap
2 a1 a2
intercept tap
3 a1 a2
*/

调用hook interceptor 方法,根据传入配置的不同会再特定的时候对参数或者执行时进行拦截。
上述打印的函数中展示了在发布时,对于interceptor中的call,loop和tap钩子的调用过程;
loop方法只在有循环的条件时调用。
剩下的register方法是在订阅时拦截订阅函数的参数,处理后返回参数。

    intercept(interceptor) {
        this._resetCompilation();
        this.interceptors.push(Object.assign({}, interceptor));
        if (interceptor.register) {
            for (let i = 0; i < this.taps.length; i++) {
                this.taps[i] = interceptor.register(this.taps[i]);
            }
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容