服务器推送事件与轮询的比较

80

在性能、浏览器实现可用性、服务器负载等方面,HTML5 SSEs和纯粹的Ajax轮询之间是否存在很大差异?从服务器端来看,似乎一个EventSource只是每隔约3秒钟(尽管我知道时间是有弹性的)就会访问指定的页面。

可以肯定的是,与设置定时器并每隔一段时间进行$.get相比,在客户端上设置一个EventSource更为简单。但还有别的吗?它发送的标头更少,或者有一些其他的魔法吗?

2个回答

100
Ajax轮询会增加很多HTTP开销,因为它不断地建立和终止HTTP连接。正如HTML5 Rocks所说的那样:“另一方面,服务器推送事件从根本上设计为高效。” 服务器推送事件打开一个持久的HTTP连接。服务器在有数据时单向发送数据,客户端无需请求或执行任何操作,只需等待消息。
服务器推送事件的一个缺点是,它们创建了与服务器的持久连接,您可能会对您的服务器拥有许多打开的连接。一些服务器更好地处理大量并发连接,而其他服务器则不然。即便如此,您将遇到类似的轮询问题,再加上不断重新建立这些连接的开销。

服务器发送事件在大多数浏览器中得到了很好的支持, 当然,显著的例外是IE。但是有一 polyfills(以及一个jQuery插件)可以解决这个问题。

如果您只需要单向通信,则应选择使用服务器发送事件。正如您所提到的,服务器发送事件倾向于在客户端实现时更加简单和清晰。您只需为消息和事件设置侦听器,浏览器会处理低级别的事情,例如重新连接等。在服务器端,也相当容易实现,因为它只使用简单的文本。如果您发送JSON编码的对象,则可以通过JSON.parse()将它们轻松转换为JavaScript对象。

如果您在服务器上使用PHP,您可以使用json_encode()将字符串、数字、数组和对象转换为正确编码的JSON。其他后端语言也可能提供类似的功能。

6
但是服务器端的资源怎么办?每5秒钟发送1个ajax请求不比为每个用户永久保持连接更好吗? - Enrique
1
使用SSE有一些注意事项,其中两个比较重要的是它们只接受GET请求,并且不允许您指定标头。 - Nicolas
你会遇到的一个问题是 Apache 上的 max_children,请参见:“PHP 中的 SSE - Apache 挂起并且不注册/服务任何新请求”→ https://dev59.com/Ncj6oIgBc1ULPQZFQ19N - Avatar
你会遇到的一个问题是Apache上的max_children,请参考: "SSE in PHP - Apache hanging and not registering/serving any new requests" → https://dev59.com/Ncj6oIgBc1ULPQZFQ19N - Avatar

6
我只想在已经说过的基础上增加一个更高层次的观点,那就是SSE是发布订阅模型,而AJAX则需要不断轮询。通常,这两种方式(轮询和发布订阅)都在试图解决如何在客户端上保持最新状态的问题。
1) 轮询模型
这很简单。客户端(浏览器)首先获取一个初始状态(页面),要更新它,就需要定期请求状态(页面或其部分)并将结果处理成当前状态(在AJAX的情况下整个页面刷新或智能地渲染为其部分)。
自然而然的缺点是,如果服务器状态没有发生变化,资源(CPU,网络等)会被无谓地使用。另一个缺点是,即使状态发生改变,客户端也只会在下一次轮询周期中收到,而不是尽快得到。人们通常需要评估好时间折衷方案。
线程中的自旋锁就是轮询的另一个例子。
2) 发布订阅模型
它的工作方式如下:
- 客户端首先请求并显示一些初始状态 - 客户端订阅服务器(发送一个请求,可能带有一些上下文,如事件源) - 服务器将客户端的引用标记到某个其客户端引用存储库中 - 如果状态更新,服务器将根据其保存的客户端引用向客户端发送通知;即它不是对请求的响应,而是由服务器发起的消息。 - 好的客户端在不再感兴趣的通知时取消订阅。
这就是SSE,或者在线程中是可等待事件,作为另一个例子。自然而然的缺点是,服务器必须知道所有已订阅的客户端,在某些实现中可能会成为问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接