1

这实际上是一个更抽象的问题。我如何确保不会错过 WebSocket 的 open 事件?据我了解,只要我调用构造函数,浏览器就会开始建立连接,所以如果事情不顺利,可能会在连接这些事件的处理程序之前触发一个打开(或错误)事件。

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 在这方面有所不同?我是否忽略了某些事情并且错过了该事件并不是真正的问题?

感谢您对此进行澄清。

4

1 回答 1

3

您使用 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 坚持它。

于 2013-04-18T16:15:59.910 回答