我在WebSocket
中使用javascript
。 WebSocket
需要url作为构造函数参数并立即尝试连接。我只能在构造它之后设置onopen
方法。
因此,如果WebSocket
在设置onopen
之前已经建立了连接,那么我会错过onopen
事件!
我该如何避免这种情况?
模拟它:
A)
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)我们错过了它!
答案 0 :(得分:4)
由于Javascript的单线程事件驱动特性,您所描述的内容不会在实际代码中发生。 "打开"在您当前的Javascript部分完成之后,才能触发事件。因此,您始终可以在事件发生之前设置onopen
事件处理程序。
在调试器或控制台中插入人为暂停是一种人为的情况,在实际代码中不会发生。
实际代码中会发生什么:
new WebSocket(uri)
.onopen
属性并设置事件处理程序。open
事件,Javascript将触发该事件,导致您的.onopen
处理程序被调用。open
事件尚未完成,Javascript将等待下一个事件插入到事件队列中并运行它,一遍又一遍地重复该过程。最终,其中一项活动将是您的open
活动。关键是通过异步事件调用.onopen
。因此,它必须通过Javascript事件队列。并且,直到您当前的Javascript部分完成并返回到解释器之后,才能运行事件队列中的事件。那是"事件驱动的" Javascript的本质是有效的。因此,由于该体系结构,只要您在调用构造函数的Javascript的同一部分中安装onopen
处理程序,就不会错过.onopen
事件。
如果它给你带来任何舒适感,那么node.js中有许多API都依赖于同样的概念。例如,当您使用fs.createReadStream(filename)
创建文件流时,您必须创建流,然后添加事件处理程序(其中一个事件处理程序用于open
事件)。同样的逻辑适用于那里。由于Javascript的事件驱动性质,没有竞争条件。在其余的Javascript运行之前,无法触发open
事件或error
事件,因此您始终有机会安装事件处理程序,然后才能调用它们。
如果可以同步检测到错误(如错误的文件名或错误的uri)并且可能立即触发error
事件,则使用setImmediate(function() { /* send error event here*/ })
之类的代码进行编码以确保错误事件不是在您的代码有机会安装事件处理程序之前触发。