我在WebSocket中使用javascriptWebSocket需要将该url作为构造函数参数,并立即尝试连接。我只能在构造onopen方法后设置它。

因此,如果WebSocket在设置onopen之前已经建立了连接,那么我会错过onopen事件!

如何避免这种情况?

要模拟它:

一种)

1)在Chrome中,打开websocket
2)按F12打开开发人员工具。
3)打开控制台
4)一次复制并粘贴所有这些代码!输入!

uri = "ws://echo.websocket.org?encoding=text";
websocket = new WebSocket(uri);
websocket.onopen = function(evt) { console.log('EHE')};


B)

重复1-2-3

4)复制并粘贴这些代码并运行

uri = "ws://echo.websocket.org?encoding=text";
websocket = new WebSocket(uri);


5)等一下

6)运行这段代码:

websocket.onopen = function(evt) { console.log('EHE')};


结果:

在A)中,调用onopen。在B)中我们错过了!

最佳答案

由于Java脚本具有单线程事件驱动的特性,因此您描述的内容不会在实际代码中发生。只有在您当前的Java语言部分完成后,才能触发“打开”事件。因此,您始终可以在事件发生之前设置onopen事件处理程序。

在调试器或控制台中插入人为的暂停是在实际代码中不会发生的人为情况。

实际代码中发生的事情是这样的:


您致电new WebSocket(uri)
webSocket内部结构启动webSocket连接(异步操作)
该连接完成之前,webSocket构造函数立即返回。
您其余的代码将运行(包括分配.onopen属性和设置事件处理程序)。
Java解释器完成了您的代码的运行,并返回到事件循环。
如果到目前为止,如果webSocket已连接,则事件队列中将存在一个open事件,并且Javascript将触发该事件,从而导致您的.onopen处理程序被调用。
如果open事件尚未完成,则Javascript将等待下一个事件插入事件队列并运行它,一遍又一遍地重复该过程。最终,这些事件之一将是您的open事件。


关键在于通过异步事件调用.onopen。因此,它必须经过Javascript事件队列。而且,直到您当前的Javascript部分完成并返回到解释器之前,事件队列中的任何事件都无法运行。这就是JavaScript的“事件驱动”本质的工作方式。因此,由于采用了这种架构,只要将onopen处理程序安装在调用构造函数的Javascript的同一部分中,就不能错过.onopen事件。



如果给您带来任何舒适,node.js中有数十个API都依赖于同一概念。例如,当您使用fs.createReadStream(filename)创建文件流时,必须先创建流,然后添加事件处理程序(其中一个事件处理程序用于open事件)。相同的逻辑在那里适用。由于Javascript具有事件驱动的特性,因此没有竞争条件。 open事件或error事件无法在Javascript的其余部分运行之前被触发,因此您总是有机会在事件处理程序被调用之前先进行安装。

如果可能同时检测到错误(例如文件名错误或uri错误)并可能立即触发error事件,则使用类似setImmediate(function() { /* send error event here*/ })的代码进行编码,以确保在代码包含有机会安装事件处理程序。

关于javascript - 我如何保证websocket onopen被调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49210034/

10-09 15:12