From 9f5a4bdb0b5694a63d91a718248b59beaf40995f Mon Sep 17 00:00:00 2001 From: Kuitos Date: Mon, 11 Mar 2024 21:03:29 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20optimize=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sandbox/patchers/windowListener.ts | 74 ++++++++++++-------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/src/sandbox/patchers/windowListener.ts b/src/sandbox/patchers/windowListener.ts index 8d08cfc15..e09b49d8b 100644 --- a/src/sandbox/patchers/windowListener.ts +++ b/src/sandbox/patchers/windowListener.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-param-reassign */ /** * @author Kuitos * @since 2019-04-11 @@ -17,63 +16,61 @@ type ListenerMapObject = { const DEFAULT_OPTIONS: AddEventListenerOptions = { capture: false, once: false, passive: false }; -// 移除cacheListener +const normalizeOptions = (rawOptions?: boolean | AddEventListenerOptions): 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,确保它是一个对象 - let options = typeof rawOptions === 'object' ? rawOptions : { capture: !!rawOptions }; - // 如果 options 为 null,使用默认值 - options = options ?? DEFAULT_OPTIONS; - + 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,确保它是一个对象 - let options = typeof rawOptions === 'object' ? rawOptions : { capture: !!rawOptions }; - // 如果 options 为 null,使用默认值 - options = options ?? DEFAULT_OPTIONS; - + 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]); + cachedTypeListeners.push(cacheListener); + listenerMap.set(type, cachedTypeListeners); return cacheListener; }; @@ -86,10 +83,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 = ( @@ -98,18 +94,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 noop; }; }