From 6d252c6919527d6a10780132fe67eb1c232106f6 Mon Sep 17 00:00:00 2001 From: Kuitos Date: Mon, 11 Mar 2024 21:25:45 +0800 Subject: [PATCH] chore: optimize code (#2925) --- .changeset/smart-guests-jam.md | 5 ++ .../sandbox/src/patchers/windowListener.ts | 74 +++++++++---------- 2 files changed, 40 insertions(+), 39 deletions(-) create mode 100644 .changeset/smart-guests-jam.md diff --git a/.changeset/smart-guests-jam.md b/.changeset/smart-guests-jam.md new file mode 100644 index 000000000..4d09cf8b1 --- /dev/null +++ b/.changeset/smart-guests-jam.md @@ -0,0 +1,5 @@ +--- +"@qiankunjs/sandbox": patch +--- + +chore: optimize code diff --git a/packages/sandbox/src/patchers/windowListener.ts b/packages/sandbox/src/patchers/windowListener.ts index 242bf5da9..c92c36d0d 100644 --- a/packages/sandbox/src/patchers/windowListener.ts +++ b/packages/sandbox/src/patchers/windowListener.ts @@ -1,8 +1,8 @@ -/* eslint-disable no-param-reassign */ /** * @author Kuitos * @since 2019-04-11 */ +import { type Free } from './types'; const rawAddEventListener = window.addEventListener; const rawRemoveEventListener = window.removeEventListener; @@ -15,67 +15,64 @@ type ListenerMapObject = { const DEFAULT_OPTIONS: AddEventListenerOptions = { capture: false, once: false, passive: false }; -// 移除cacheListener +const normalizeOptions = (rawOptions?: boolean | AddEventListenerOptions | null): AddEventListenerOptions => { + if (typeof rawOptions === 'object') { + return rawOptions ?? DEFAULT_OPTIONS; + } + return { capture: !!rawOptions, once: false, passive: false }; +}; + +const findListenerIndex = ( + listeners: ListenerMapObject[], + rawListener: EventListenerOrEventListenerObject, + options: AddEventListenerOptions, +): number => + listeners.findIndex((item) => item.rawListener === rawListener && item.options.capture === options.capture); + const removeCacheListener = ( listenerMap: Map, type: string, rawListener: EventListenerOrEventListenerObject, rawOptions?: boolean | AddEventListenerOptions, ): ListenerMapObject => { - // 如果 options 为 null、undefined,使用默认值 - const opts = rawOptions ?? DEFAULT_OPTIONS; - // 处理 options,确保它是一个对象 - const options = typeof opts === 'object' ? opts : { capture: !!opts }; - + const options = normalizeOptions(rawOptions); const cachedTypeListeners = listenerMap.get(type) || []; - // listener和capture/useCapture都相同,认为是同一个监听 - // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener - const findIndex = cachedTypeListeners.findIndex( - (item) => item.rawListener === rawListener && item.options.capture == options.capture, - ); + + const findIndex = findListenerIndex(cachedTypeListeners, rawListener, options); if (findIndex > -1) { - const cacheListener = cachedTypeListeners[findIndex]; - cachedTypeListeners.splice(findIndex, 1); - return cacheListener; + return cachedTypeListeners.splice(findIndex, 1)[0]; } - // 返回原始listener和options return { listener: rawListener, rawListener, options }; }; -// 添加监听构造一个cacheListener对象,考虑到多次添加同一个监听和once的情况 const addCacheListener = ( listenerMap: Map, type: string, rawListener: EventListenerOrEventListenerObject, rawOptions?: boolean | AddEventListenerOptions, ): ListenerMapObject | undefined => { - // 如果 options 为 null、undefined,使用默认值 - const opts = rawOptions ?? DEFAULT_OPTIONS; - // 处理 options,确保它是一个对象 - const options = typeof opts === 'object' ? opts : { capture: !!opts }; - + const options = normalizeOptions(rawOptions); const cachedTypeListeners = listenerMap.get(type) || []; - // listener和capture/useCapture都相同,认为是同一个监听 - // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener - const findIndex = cachedTypeListeners.findIndex( - (item) => item.rawListener === rawListener && item.options.capture == options.capture, - ); - // 如果事件已经添加到了target的event listeners 列表中,直接返回不需要添加第二次 + + const findIndex = findListenerIndex(cachedTypeListeners, rawListener, options); + // avoid duplicated listener in the listener list if (findIndex > -1) return; let listener: EventListenerOrEventListenerObject = rawListener; - if (options.once) + if (options.once) { listener = (event: Event) => { (rawListener as EventListener)(event); removeCacheListener(listenerMap, type, rawListener, options); }; + } + const cacheListener = { listener, options, rawListener }; listenerMap.set(type, [...cachedTypeListeners, cacheListener]); return cacheListener; }; -export default function patch(global: WindowProxy) { +export default function patch(global: WindowProxy): Free { const listenerMap = new Map(); global.addEventListener = ( @@ -84,10 +81,9 @@ export default function patch(global: WindowProxy) { rawOptions?: boolean | AddEventListenerOptions, ) => { const addListener = addCacheListener(listenerMap, type, rawListener, rawOptions); - // 如果返回空,则代表事件已经添加过了,不需要重复添加 + if (!addListener) return; - const { listener, options } = addListener; - return rawAddEventListener.call(window, type, listener, options); + return rawAddEventListener.call(global, type, addListener.listener, addListener.options); }; global.removeEventListener = ( @@ -96,18 +92,18 @@ export default function patch(global: WindowProxy) { rawOptions?: boolean | AddEventListenerOptions, ) => { const { listener, options } = removeCacheListener(listenerMap, type, rawListener, rawOptions); - return rawRemoveEventListener.call(window, type, listener, options); + return rawRemoveEventListener.call(global, type, listener, options); }; return function free() { - listenerMap.forEach((listeners, type) => - [...listeners].forEach(({ rawListener, options }) => global.removeEventListener(type, rawListener, options)), - ); - // 清空listenerMap,避免listenerMap中还存有listener导致内存泄漏 + listenerMap.forEach((listeners, type) => { + listeners.forEach(({ rawListener, options }) => { + global.removeEventListener(type, rawListener, options); + }); + }); listenerMap.clear(); global.addEventListener = rawAddEventListener; global.removeEventListener = rawRemoveEventListener; - return () => Promise.resolve(); }; }