-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dispatched events are not scheduled as tasks #2159
Comments
Yes, To match the browser behavior only a single |
@KhafraDev fyi, the WebSocket implementation in https://github.com/nodejs/undici has the same non spec compliant behavior. |
To improve compatibility with the WHATWG standard, emit at most one of `'message'`, `'ping'`, and `'pong'` events per tick. Fixes #2159
To improve compatibility with the WHATWG standard, emit at most one of `'message'`, `'ping'`, and `'pong'` events per tick. Fixes #2159
@lpinca thanks! |
In puppeteer, we worked around the problem by scheduling all event handlers triggered by 'ws' using |
Here are some benchmark results run under WSL 2.
|
On macOS with 250 clients I see no significant overhead. If you are using Linux on bare metal, may I ask you to run some benchmarks like the ones above (increasing the number of clients up to 1000 might make sense)? Thank you. |
Unfortunately, I don't have a Linux on bare metal. |
This is the numbers I get on an Intel Macbook (node 20):
|
It seems to be consistent with my results (~10% impact). We can make this behavior optional by using and option that can be passed to the server and the client like the
Another option is an env variable like |
My opinion would be that it's better to match the spec by default and have performance optimisations as an opt-in. Also, I think the change does not have to apply to the server implementation as only the client-side events are spec'ed. I assume that clients handle fewer messages than servers so it might have lower impact on performance and would match the browser's implementations. Maybe if the change applies only to the clients, there will be no need to configure this behaviour? |
I'm not sure I agree. The current behavior is not a bug and there are other areas where we diverge from the WHATWG spec. A client in another language with a completely different interface is still a valid client as long as it follows RFC 6455, RFC 7692, etc. We try to be compatible with the WHATWG spec for convenience.
The same |
That makes sense to me too.
Yeah, might be confusing if both client and server are used (especially within one codebase). We so far only had the need for the client. |
Yes, that is basically my point. In all these years this is the first time this is reported and as written in my first comment I don't think there is much code that depends on this behavior. This is why I would prefer to make it opt-in. On the other hand making it opt-in kind of defeats the compatibility goal as the code would not be portable. I wonder if there is some way to reduce the performance impact. |
Surprisingly this diff --git a/lib/receiver.js b/lib/receiver.js
index c7dcf8a..f4497b4 100644
--- a/lib/receiver.js
+++ b/lib/receiver.js
@@ -165,17 +165,12 @@ class Receiver extends Writable {
// `WAIT_MICROTASK`.
this._loop = false;
- const next = () => {
+ // `queueMicrotask()` is a little slower and is not available in
+ // Node.js < 11.
+ Promise.resolve().then(() => {
this._state = GET_INFO;
this.startLoop(cb);
- };
-
- if (typeof queueMicrotask === 'function') {
- queueMicrotask(next);
- } else {
- // `queueMicrotask()` is not available in Node.js < 11.
- Promise.resolve().then(next);
- }
+ });
return;
}
is a little faster. I'll keep investigating. |
Some numbers from a virtual Linux:
|
I have quickly tried wrapping all emit calls in |
Simply deferring the |
To improve compatibility with the WHATWG standard, emit at most one of `'message'`, `'ping'`, and `'pong'` events per tick. Fixes #2159
To improve compatibility with the WHATWG standard, emit at most one of `'message'`, `'ping'`, and `'pong'` events per tick. Fixes #2159
To improve compatibility with the WHATWG standard, emit at most one of `'message'`, `'ping'`, and `'pong'` events per tick. Fixes #2159
Is there an existing issue for this?
Description
I am not sure this is a bug or rather a topic for discussion. I have noticed that there is a subtle difference between
ws
and the WebSockets standard. The standard says that when a message is received the agent has to queue a new task. This has an important side effect that the microtask queue will be processed after the task is over and before the next task is picked from the queue. This behaviour is important in the cases where the messages need to be processed in a specified order.This can be demonstrated by the following server code:
And the client code:
If you run this code in Node and in the browser, you should observe that the order of console messages is different. It's probably not feasible to change the behaviour of 'ws' as it could be a breaking change but I wonder if there could be some compatibility mode for this? I believe it's possible to workaround that using setTimeout or setImmediate but the downside is that the same code cannot be used across platforms. If I have overlooked an existing issue about this topic, I apologize.
ws version
8.13.0
Node.js Version
v20.3.1
System
System:
OS: macOS 13.5
CPU: (10) arm64 Apple M1 Max
Memory: 696.63 MB / 64.00 GB
Shell: 5.9 - /bin/zsh
Expected result
The order of console messages is the same in Node and in the browser and matches the behaviour defined by the standard:
Actual result
The order of console messages in Node is different (microtasks are processed after all messages):
Attachments
No response
The text was updated successfully, but these errors were encountered: