Skip to content

Commit 9ab743a

Browse files
committed
[feature] Add support for objets with a handleEvent() method
Make `WebSocket.prototype.addEventListener()` support an event listener specified as an object with a `handleEvent()` method. Fixes #2092
1 parent 38f7879 commit 9ab743a

File tree

3 files changed

+37
-18
lines changed

3 files changed

+37
-18
lines changed

doc/ws.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ handshake. This allows you to read headers from the server, for example
426426
### websocket.addEventListener(type, listener[, options])
427427

428428
- `type` {String} A string representing the event type to listen for.
429-
- `listener` {Function} The listener to add.
429+
- `listener` {Function|Object} The listener to add.
430430
- `options` {Object}
431431
- `once` {Boolean} A `Boolean` indicating that the listener should be invoked
432432
at most once after being added. If `true`, the listener would be
@@ -555,7 +555,7 @@ The current state of the connection. This is one of the ready state constants.
555555
### websocket.removeEventListener(type, listener)
556556

557557
- `type` {String} A string representing the event type to remove.
558-
- `listener` {Function} The listener to remove.
558+
- `listener` {Function|Object} The listener to remove.
559559

560560
Removes an event listener emulating the `EventTarget` interface. This method
561561
only removes listeners added with

lib/event-target.js

+22-6
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ const EventTarget = {
178178
* Register an event listener.
179179
*
180180
* @param {String} type A string representing the event type to listen for
181-
* @param {Function} listener The listener to add
181+
* @param {(Function|Object)} listener 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
@@ -196,7 +196,7 @@ const EventTarget = {
196196
});
197197

198198
event[kTarget] = this;
199-
listener.call(this, event);
199+
callListener(listener, this, event);
200200
};
201201
} else if (type === 'close') {
202202
wrapper = function onClose(code, message) {
@@ -207,7 +207,7 @@ const EventTarget = {
207207
});
208208

209209
event[kTarget] = this;
210-
listener.call(this, event);
210+
callListener(listener, this, event);
211211
};
212212
} else if (type === 'error') {
213213
wrapper = function onError(error) {
@@ -217,14 +217,14 @@ const EventTarget = {
217217
});
218218

219219
event[kTarget] = this;
220-
listener.call(this, event);
220+
callListener(listener, this, event);
221221
};
222222
} else if (type === 'open') {
223223
wrapper = function onOpen() {
224224
const event = new Event('open');
225225

226226
event[kTarget] = this;
227-
listener.call(this, event);
227+
callListener(listener, this, event);
228228
};
229229
} else {
230230
return;
@@ -244,7 +244,7 @@ const EventTarget = {
244244
* Remove an event listener.
245245
*
246246
* @param {String} type A string representing the event type to remove
247-
* @param {Function} handler The listener to remove
247+
* @param {(Function|Object)} handler The listener to remove
248248
* @public
249249
*/
250250
removeEventListener(type, handler) {
@@ -264,3 +264,19 @@ module.exports = {
264264
EventTarget,
265265
MessageEvent
266266
};
267+
268+
/**
269+
* Call an event listener
270+
*
271+
* @param {(Function|Object)} listener The listener to call
272+
* @param {*} thisArg The value to use as `this`` when calling the listener
273+
* @param {Event} event The event to pass to the listener
274+
* @private
275+
*/
276+
function callListener(listener, thisArg, event) {
277+
if (typeof listener === 'object' && listener.handleEvent) {
278+
listener.handleEvent.call(listener, event);
279+
} else {
280+
listener.call(thisArg, event);
281+
}
282+
}

test/websocket.test.js

+13-10
Original file line numberDiff line numberDiff line change
@@ -3264,14 +3264,15 @@ describe('WebSocket', () => {
32643264

32653265
assert.strictEqual(ws.listenerCount('open'), 1);
32663266

3267-
ws.addEventListener(
3268-
'message',
3269-
() => {
3267+
const listener = {
3268+
handleEvent() {
32703269
events.push('message');
3270+
assert.strictEqual(this, listener);
32713271
assert.strictEqual(ws.listenerCount('message'), 0);
3272-
},
3273-
{ once: true }
3274-
);
3272+
}
3273+
};
3274+
3275+
ws.addEventListener('message', listener, { once: true });
32753276

32763277
assert.strictEqual(ws.listenerCount('message'), 1);
32773278

@@ -3318,17 +3319,19 @@ describe('WebSocket', () => {
33183319
it('supports the `removeEventListener` method', () => {
33193320
const ws = new WebSocket('ws://localhost', { agent: new CustomAgent() });
33203321

3321-
ws.addEventListener('message', NOOP);
3322+
const listener = { handleEvent() {} };
3323+
3324+
ws.addEventListener('message', listener);
33223325
ws.addEventListener('open', NOOP);
33233326

3324-
assert.strictEqual(ws.listeners('message')[0][kListener], NOOP);
3327+
assert.strictEqual(ws.listeners('message')[0][kListener], listener);
33253328
assert.strictEqual(ws.listeners('open')[0][kListener], NOOP);
33263329

33273330
ws.removeEventListener('message', () => {});
33283331

3329-
assert.strictEqual(ws.listeners('message')[0][kListener], NOOP);
3332+
assert.strictEqual(ws.listeners('message')[0][kListener], listener);
33303333

3331-
ws.removeEventListener('message', NOOP);
3334+
ws.removeEventListener('message', listener);
33323335
ws.removeEventListener('open', NOOP);
33333336

33343337
assert.strictEqual(ws.listenerCount('message'), 0);

0 commit comments

Comments
 (0)