EventSource调用removeEventListener无法移除绑定事件问题
问题原因
- 单一handler引用被覆盖:闭包内仅声明了一个全局
handle变量,每次调用addEventListener都会用新的函数引用覆盖该变量,之前绑定事件时使用的handler引用会直接丢失。调用removeEventListener时传入的是最后一次赋值的handler,无法匹配此前绑定的事件回调,导致移除失败。 - 缺少事件映射关系:没有存储「事件名-原回调函数-包装后handler」的对应关系,既不支持同一事件绑定多个回调,也无法精准匹配要移除的回调。
- 状态判断逻辑存在隐患:
es初始化后会被赋值为EventSource实例,本身不存在sseinit属性,判断条件容错性极低,未初始化时调用移除方法容易触发异常。
修复方案
修正后的封装代码如下:
var sse = {}; (function(s){ // 单独维护初始化状态,不绑定到es对象 let isSseInit = false; let es = null; // 存储事件映射:key为事件名,value为[{originalCallback, wrappedHandler}] const eventMap = {}; s.init = function (url) { if (isSseInit) return; if (typeof EventSource === 'function') { es = new EventSource(url); isSseInit = true; } else { es = {}; console.warn('当前环境不支持EventSource'); } }; s.close = function () { if (!isSseInit || !es) return; es.close(); // 清空所有绑定的事件 Object.keys(eventMap).forEach(eventName => { eventMap[eventName].forEach(({ wrappedHandler }) => { es.removeEventListener(eventName, wrappedHandler); }); delete eventMap[eventName]; }); es = null; isSseInit = false; }; s.addEventListener = function (name, callback) { if (!isSseInit || !es) return; const wrappedHandler = function(e) { callback(e, JSON.parse(e.data)); }; if (!eventMap[name]) eventMap[name] = []; eventMap[name].push({ originalCallback: callback, wrappedHandler: wrappedHandler }); es.addEventListener(name, wrappedHandler); console.log('addEventListener :: '+name); }; s.removeEventListener = function (name, callback) { if (!isSseInit || !es || !eventMap[name]) return; // 匹配对应回调的包装handler const targetIndex = eventMap[name].findIndex(item => item.originalCallback === callback); if (targetIndex === -1) return; const { wrappedHandler } = eventMap[name].splice(targetIndex, 1)[0]; es.removeEventListener(name, wrappedHandler); if (eventMap[name].length === 0) delete eventMap[name]; console.log('removeEventListener :: '+name); }; }(sse));
使用注意事项
- 调用
removeEventListener时,必须传入和绑定时完全相同的回调函数引用,不要传入匿名函数,否则无法匹配移除。 - 支持同一事件绑定多个不同回调,各自可独立移除,互不影响。
- 修复了原代码中EventSource兼容性判断的逻辑错误,避免异常触发。
内容的提问来源于stack exchange,提问作者Aheuh
相关产品推荐
相关产品推荐

