question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use Node.js 15 native `EventTarget` object

See original GitHub issue
  • I’ve searched for any related issues and avoided creating a duplicate issue.

Description

Node.js 15 already provides a native implementation of EventTarget, so there’s no need to use our own implementation. In fact, using both of them at the same time leads to errors.

In my use case, I’ve created a Client class that extends from Node.js native EventTarget class, that internally it’s using an ws instance (and doing some other project specific things), and setting as listeners methods from this Client class, with the idea of propagate these errors to the user:

export class Client extends EventTarget
{
  constructor(ws)
  {
    super()

    if(!(ws instanceof WebSocket)) ws = new WebSocket(ws)

    ws.binaryType = 'arraybuffer'

    ws.addEventListener('close', this.#onClose, {once: true})
    ws.addEventListener('error', this.#onError)
    ws.addEventListener('message', this.#onMessage)
    ws.addEventListener('open', this.#onOpen, {once: true})

    this.#ws = ws
  }

  #onClose = this.dispatchEvent.bind(this)
  #onError = this.dispatchEvent.bind(this)
  #onOpen  = this.dispatchEvent.bind(this)
}

Problem is, since ws is using its own implementation of both EventTarget and Event classes, when these events gets propagated to the native one, I get the next error:

TypeError [ERR_INVALID_ARG_TYPE]: The "event" argument must be an instance of Event. Received an instance of ErrorEvent
    at new NodeError (node:internal/errors:277:15)
    at EventTarget.dispatchEvent (node:internal/event_target:326:13)
    at WebSocket.onError (/home/piranna/Trabajo/Atos/awrtc_signaling/node_modules/ws/lib/event-target.js:141:16)
    at WebSocket.emit (node:events:329:20)
    at WebSocket.EventEmitter.emit (node:domain:467:12)
    at ClientRequest.<anonymous> (/home/piranna/Trabajo/Atos/awrtc_signaling/node_modules/ws/lib/websocket.js:579:15)
    at ClientRequest.emit (node:events:329:20)
    at ClientRequest.EventEmitter.emit (node:domain:467:12)
    at TLSSocket.socketErrorListener (node:_http_client:478:9)
    at TLSSocket.emit (node:events:329:20) {
  code: 'ERR_INVALID_ARG_TYPE'
}

This is due because Node.js native EventTarget class is expecting a native Event class instance, instead of the one provided by ws. According to Node.js docs it should be accepting any object with a type field, but for some reason is not accepting it.

Reproducible in:

  • version: 7.4.0
  • Node.js version(s): 15.2.0
  • OS version(s): Ubuntu 20.10

Steps to reproduce:

  1. use Node.js 15
  2. create an object instance with Node.js 15 native EventTarget class in its prototype chain
  3. create a ws instance and call to addEventListener setting one function that propagate the event to the native EventTarget
  4. emit the event
  5. BOOM

Expected result:

ws should check for actual support of both Event and EventTarget classes in the native platform (in this case, Node.js 15) and use them. In case they are not available, then use its own implementation as a polyfill.

Actual result:

ws is using always its own implementation of Event and EventTarget classes, since there was none before, so now it conflicts with the new Node.js native available ones.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:7
  • Comments:34 (14 by maintainers)

github_iconTop GitHub Comments

3reactions
danieltrogercommented, Jul 15, 2021

If I understood correctly the spec, using on… remove all the previous handlers, both on… and addEventListener ones. That’s why on… ones are totally discouraged and unrecommended in W3C specs.

What spec? 👀

This is how it works in the browser and how I’m used to it:

Screenshot 2021-07-15 at 21 54 06
3reactions
lpincacommented, Nov 21, 2020

I prefer to keep making WebSocket inherit from EventEmitter for now.

Advantages:

  • No breaking changes.
  • No feature detection and polyfill.
  • The WebSocket class is always an EventEmitter and the documentation is the same in all supported Node.js versions.
  • No performance regressions.

Disadvantages:

  • Some compatibility issues between the very simple ws EventTarget implementation and the Node.js EventTarget implementation.

That said, I think making WebSocket inherit from NodeEventTarget is something worth exploring.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Events | Node.js v19.3.0 Documentation
The NodeEventTarget object implements a modified subset of the EventEmitter API that allows it to closely emulate an EventEmitter in certain situations. A ......
Read more >
Node.js and the struggles of being an EventTarget - NearForm
Loosely speaking, an EventTarget is a JavaScript object that is associated with a list of event types, i.e. strings, on which event listeners ......
Read more >
EventTarget - Web APIs | MDN
Chrome Edge EventTarget Full support. Chrome1. Toggle history Full support. Edg... EventTarget() constructor Full support. Chrome64. Toggle history Full support. Edg... addEventListener Full support. Chrome1. footnote....
Read more >
How to use JavaScript EventTarget? - Stack Overflow
Emitter.prototype = Object. · EventTarget is just an interface, not a constructor. Also, you cannot inherit from native DOM structures. · Bergi, ...
Read more >
How To Handle DOM and Window Events with React
In JavaScript apps using the React front-end library, you can use event handlers to update state data, trigger prop changes, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found