微前端框架 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

 

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