微前端框架 qiankun 源码解读 1.2 hijackers/historyListener

import { isFunction, noop } from 'lodash';

export default function hijack() {
  let rawHistoryListen = (_: any) => noop;
  const historyListeners: Array<typeof noop> = [];
  const historyUnListens: Array<typeof noop> = [];

函数开始声明了一个函数,两个数组用来保存history监听器。

  if ((window as any).g_history && isFunction((window as any).g_history.listen)) {
    rawHistoryListen = (window as any).g_history.listen.bind((window as any).g_history);

    (window as any).g_history.listen = (listener: typeof noop) => {
      historyListeners.push(listener);

      const unListen = rawHistoryListen(listener);
      historyUnListens.push(unListen);

      return () => {
        unListen();
        historyUnListens.splice(historyUnListens.indexOf(unListen), 1);
        historyListeners.splice(historyListeners.indexOf(listener), 1);
      };
    };
  }

与劫持window监听器相同,先保存window.g_history.listen函数,再对其重写。多了往historyListeners添加本次listen的副作用。

返回执行unListen和移除数组中本次listen的函数。

  return function free() {
    let rebuild = noop;

    /*
     还存在余量 listener 表明未被卸载,存在两种情况
     1. 应用在 unmout 时未正确卸载 listener
     2. listener 是应用 mount 之前绑定的,
     第二种情况下应用在下次 mount 之前需重新绑定该 listener
     */
    if (historyListeners.length) {
      rebuild = () => {
        // 必须使用 window.g_history.listen 的方式重新绑定 listener,从而能保证 rebuild 这部分也能被捕获到,否则在应用卸载后无法正确的移除这部分副作用
        historyListeners.forEach(listener => (window as any).g_history.listen(listener));
      };
    }

    // 卸载余下的 listener
    historyUnListens.forEach(unListen => unListen());

    // restore
    if ((window as any).g_history && isFunction((window as any).g_history.listen)) {
      (window as any).g_history.listen = rawHistoryListen;
    }

    return rebuild;
  };
}

用rebuild函数保存需要恢复的listener,卸载所有的listener,并恢复window.g_history.listen。

返回rebuild函数用于下次恢复需要的listener。

 

qiankun源码:https://github.com/umijs/qiankun

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章