Skip to content

Commit 1cec17d

Browse files
committedNov 6, 2022
[fix] Add the same event listener only once
Prevent `WebSocket.prototype.addEventListener()` from adding the same event listener multiple times.
1 parent 9ab743a commit 1cec17d

File tree

2 files changed

+41
-24
lines changed

2 files changed

+41
-24
lines changed
 

‎lib/event-target.js

+17-7
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,25 @@ const EventTarget = {
178178
* Register an event listener.
179179
*
180180
* @param {String} type A string representing the event type to listen for
181-
* @param {(Function|Object)} listener The listener to add
181+
* @param {(Function|Object)} handler The listener to add
182182
* @param {Object} [options] An options object specifies characteristics about
183183
* the event listener
184184
* @param {Boolean} [options.once=false] A `Boolean` indicating that the
185185
* listener should be invoked at most once after being added. If `true`,
186186
* the listener would be automatically removed when invoked.
187187
* @public
188188
*/
189-
addEventListener(type, listener, options = {}) {
189+
addEventListener(type, handler, options = {}) {
190+
for (const listener of this.listeners(type)) {
191+
if (
192+
!options[kForOnEventAttribute] &&
193+
listener[kListener] === handler &&
194+
!listener[kForOnEventAttribute]
195+
) {
196+
return;
197+
}
198+
}
199+
190200
let wrapper;
191201

192202
if (type === 'message') {
@@ -196,7 +206,7 @@ const EventTarget = {
196206
});
197207

198208
event[kTarget] = this;
199-
callListener(listener, this, event);
209+
callListener(handler, this, event);
200210
};
201211
} else if (type === 'close') {
202212
wrapper = function onClose(code, message) {
@@ -207,7 +217,7 @@ const EventTarget = {
207217
});
208218

209219
event[kTarget] = this;
210-
callListener(listener, this, event);
220+
callListener(handler, this, event);
211221
};
212222
} else if (type === 'error') {
213223
wrapper = function onError(error) {
@@ -217,21 +227,21 @@ const EventTarget = {
217227
});
218228

219229
event[kTarget] = this;
220-
callListener(listener, this, event);
230+
callListener(handler, this, event);
221231
};
222232
} else if (type === 'open') {
223233
wrapper = function onOpen() {
224234
const event = new Event('open');
225235

226236
event[kTarget] = this;
227-
callListener(listener, this, event);
237+
callListener(handler, this, event);
228238
};
229239
} else {
230240
return;
231241
}
232242

233243
wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
234-
wrapper[kListener] = listener;
244+
wrapper[kListener] = handler;
235245

236246
if (options.once) {
237247
this.once(type, wrapper);

‎test/websocket.test.js

+24-17
Original file line numberDiff line numberDiff line change
@@ -3257,10 +3257,13 @@ describe('WebSocket', () => {
32573257
ws.addEventListener('foo', () => {});
32583258
assert.strictEqual(ws.listenerCount('foo'), 0);
32593259

3260-
ws.addEventListener('open', () => {
3260+
function onOpen() {
32613261
events.push('open');
32623262
assert.strictEqual(ws.listenerCount('open'), 1);
3263-
});
3263+
}
3264+
3265+
ws.addEventListener('open', onOpen);
3266+
ws.addEventListener('open', onOpen);
32643267

32653268
assert.strictEqual(ws.listenerCount('open'), 1);
32663269

@@ -3273,9 +3276,28 @@ describe('WebSocket', () => {
32733276
};
32743277

32753278
ws.addEventListener('message', listener, { once: true });
3279+
ws.addEventListener('message', listener);
32763280

32773281
assert.strictEqual(ws.listenerCount('message'), 1);
32783282

3283+
ws.addEventListener('close', NOOP);
3284+
ws.onclose = NOOP;
3285+
3286+
let listeners = ws.listeners('close');
3287+
3288+
assert.strictEqual(listeners.length, 2);
3289+
assert.strictEqual(listeners[0][kListener], NOOP);
3290+
assert.strictEqual(listeners[1][kListener], NOOP);
3291+
3292+
ws.onerror = NOOP;
3293+
ws.addEventListener('error', NOOP);
3294+
3295+
listeners = ws.listeners('error');
3296+
3297+
assert.strictEqual(listeners.length, 2);
3298+
assert.strictEqual(listeners[0][kListener], NOOP);
3299+
assert.strictEqual(listeners[1][kListener], NOOP);
3300+
32793301
ws.emit('open');
32803302
ws.emit('message', EMPTY_BUFFER, false);
32813303

@@ -3353,21 +3375,6 @@ describe('WebSocket', () => {
33533375
assert.strictEqual(ws.listenerCount('message'), 0);
33543376
assert.strictEqual(ws.listenerCount('open'), 0);
33553377

3356-
// Multiple listeners.
3357-
ws.addEventListener('message', NOOP);
3358-
ws.addEventListener('message', NOOP);
3359-
3360-
assert.strictEqual(ws.listeners('message')[0][kListener], NOOP);
3361-
assert.strictEqual(ws.listeners('message')[1][kListener], NOOP);
3362-
3363-
ws.removeEventListener('message', NOOP);
3364-
3365-
assert.strictEqual(ws.listeners('message')[0][kListener], NOOP);
3366-
3367-
ws.removeEventListener('message', NOOP);
3368-
3369-
assert.strictEqual(ws.listenerCount('message'), 0);
3370-
33713378
// Listeners not added with `websocket.addEventListener()`.
33723379
ws.on('message', NOOP);
33733380

0 commit comments

Comments
 (0)
Please sign in to comment.