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