这其实是一个比较抽象的问题。我怎样才能确保我没有错过WebSocket的打开事件?根据我的理解,只要我调用构造函数,浏览器就会开始建立连接,所以如果事情不顺利,在连接这些事件的处理程序之前,可能会触发一个打开(或错误)事件。
var socket = new WebSocket("ws://www.example.com");
/*Because I'm an unlucky guy, the open-event fires before the next line*/
socket.addEventListener("open", function(event){...});
在这种情况下,我的open-Handler永远不会被调用。这很可能不是一个真正的问题,因为建立连接比执行下一行JavaScript花费的时间更长。但是,对于XMLHttpRequest也可以这样说,推荐的顺序是:
var ajax = new XMLHttpRequest();
ajax.addEventListener("load", function(event){...});
ajax.open();
ajax.send();
确保事件不会丢失。为什么WebSocket在这方面有所不同?我是不是忽略了什么,错过了这个活动其实不是问题?
谢谢你的解释
第二个Ajax示例有一个错误的假设。对于Ajax,将事件处理程序放在send
调用之后没有实际问题,只要它们包含在相同的同步操作集中即可。下面是一个发送Ajax请求、消耗几秒钟(完成获取的足够时间)、然后附加侦听器的小提琴。如您所见,事件运行正常。
所以,这是可以的:
var ajax = new XMLHttpRequest();
ajax.open();
ajax.send();
ajax.addEventListener("load", function(event){...});
由于浏览器JavaScript的单线程特性,load
事件实际上不会触发,直到当前代码完成运行。(注意:也许这种行为在旧的浏览器中是不同的,但它肯定是在任何支持WebSockets的浏览器中工作的。)
,然而,是不是好:
var ajax = new XMLHttpRequest();
ajax.open();
ajax.send();
setTimeout(function() {
ajax.addEventListener("load", function(event){...});
}, 1000);
这是因为您在两个异步操作之间创建了一个竞争条件:setTimeout
解析和load
事件触发。只要触发Ajax请求和设置侦听器之间的延迟处于相同的同步执行中,就不会有"丢失"Ajax事件的风险。
它的工作方式与WebSockets相同——你不会错过open
事件,只要你构造WebSocket
并在相同的同步指令集中附加监听器。下面是另一个类似于WebSocket的同步等待。正如您所看到的,即使在等待几秒钟来附加事件侦听器之后,它仍然会触发。
我不知道"在行动之前先联系听众"的做法是从哪里来的。也许它在旧的浏览器中很重要,或者对于Ajax以外的一些api也很重要。无论这种做法的原因是什么,您实际上都不需要在Ajax或WebSockets的现代浏览器中坚持它。