将自定义方法分配给 WebSocket 时如何避免竞争条件?

How to avoid race conditions when assigning custom methods to WebSocket?

当我查看有关 WebSockets 的 tutorials/documentation 时,我发现类似 this:

的代码
var ws = new WebSocket("ws://localhost:8765/dlt");
ws.onopen = () => {
  // do some very important stuff after connection has been established
  console.log("onopen");
}

但是这里的竞争条件呢?在 JavaScript 中是否以某种方式避免了?

例如此代码(仅在 连接打开后分配 onopen )将失败:

var ws = new WebSocket("ws://localhost:8765/dlt");
setTimeout(() => {
  ws.onopen = () => {
    // do some very important stuff after connection has been established
    console.log("onopen"); ///  <== won't be called
  }
}, 100);

我可以确定在连接建立之前分配已经完成吗?

(我尝试使用自定义 onopen() 方法扩展 WebSocket,但这似乎不起作用)

class MyWebSocket extends WebSocket {
  onopen() {
    console.log("onopen()");
    /// do some very important stuff after connection has been established
  }
}

你放心,这个例子没问题。 Javascript 事件循环将在承担任何其他任务之前完成当前任务。这意味着 1) WebSocket 无法在 onopen 事件之前打开连接(异步操作),2) onopen 事件处理程序将在以下周期中被调用。

另一方面,设置超时会使事情复杂化,因为事件将在当前任务之后按某种顺序调用。这意味着 WebSocket 有机会在设置处理程序之前打开连接。

你应该读一读 javascript 的事件循环:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Event_loop

如果您查看有关 Run-to-completion 的部分,您会得到以下有用的解释:

Each message is processed completely before any other message is processed. This offers some nice properties when reasoning about your program, including the fact that whenever a function runs, it cannot be pre-empted and will run entirely before any other code runs (and can modify data the function manipulates). This differs from C, for instance, where if a function runs in a thread, it may be stopped at any point by the runtime system to run some other code in another thread.

因此在您的示例中,对 ws.onopen 的赋值必须在 websocket 执行本质上异步的任何操作之前完成。通过将您的分配放在 setTimeout 内,您将它移出当前 运行 上下文,因此它可能不会在 websocket 需要它之前执行。