试想一下,每当您期待一条新消息时,就不得不重新启动 WhatsApp,或者每当您期待一场重要比赛的更新时,就需要重新加载页面。这将是非常糟糕的用户体验!
如今,用户希望用户界面能在后台信息可用时自动更新,因此,我们当然必须在应用程序中启用这些功能。
您可以使用一些技术、技巧和服务在 React 中实现实时更新。
在本篇文章中,我将概述您需要了解的技术。
无论您是要构建聊天、实时通知、多人协作功能还是其他类型的实时更新,您都一定能在这里找到适合自己的方法。
轮询还是推送,这是一个问题
实时更新方法分为两类–轮询或推送。
轮询包括在有新信息时查询服务器以获取更新。
而推送则是服务器在有新信息时立即推送给客户端。
轮询会比推送产生更多延迟,网络效率也更低,但由于轮询是基于 HTTP 的,而你无论如何都在使用 HTTP,因此它易于实现,而且普遍兼容。
正如您在本篇文章中看到的,推送可以节省资源,并有利于降低延迟。 与此同时,它需要像 WebSockets 或服务器发送事件这样的自定义技术,这可能需要一些新的阅读。
使用 fetch 进行短轮询
在 React 中实现实时更新的最简单方法之一就是让客户端每隔一段时间发送一次后台获取请求。
如果服务器上有新数据,就会在响应中返回。否则,响应就是空的。
轮询的实现很简单,但效率很低。
- 假设每隔 60 秒发出一次请求。如果在客户端检查后不久服务器上就有了更新,那么更新就必须等到下一次客户端检查(60 秒)。
- 频繁轮询可能会带来频繁更新,但会导致不必要的流量和高开销,具体取决于更新的频率。
- 每次请求都会从 HTTP 头中产生约 800 字节的开销(不含 cookie),并且在建立底层连接时会短暂延迟,可能会给用户带来明显的延迟。
建议:短轮询虽然实施简单,但在大多数情况下效率很低。只有在轮询间隔较长、新信息以可预测的速度到达,以及希望代码尽可能简单的情况下,短轮询才会偶尔派上用场–即使你承认在生产中会遇到可靠性问题。这通常不是一个好的选择,但我在此将其纳入其他方法的框架中。
使用 fetch 进行长轮询
长轮询是短轮询的优化版本,服务器不会在无更新可用时返回空响应,而是保持 HTTP 连接空闲,直到有更新共享。
通过保持连接空闲直到有更新可用,服务器可以在更新就绪后立即向客户端发送新数据。
这样就不会出现空检查,从而减少了异步请求的数量和轮询的总体开销。
这种方法也被称为 Comet,它比短轮询更有效,但远非完美。
- 虽然服务器不必再负担不必要的检查,但它现在必须无限期地保持多个连接,这就占用了内存等服务器资源。
- 这就加速了对额外服务器的需求,但由于 HTTP 的设计是无状态的,因此将有状态的空闲连接分散到多个主机上需要一种独特的负载平衡方法。
- 短轮询和长轮询都不能保证消息的顺序,也不能处理消息连续性的自动重新连接。
建议:长轮询本质上比短轮询更高效,而且实现起来也不费事,所以不妨使用长轮询。与此同时,长轮询耗费资源,而且和它的前身短轮询一样,由于每条消息都会产生开销,因此无法实现尽可能低的延迟。
服务器发送事件(SSE)
服务器发送事件(SSE)是一种浏览器 API 和协议,可让服务器在有新信息时立即推送给客户端。
不过,与每条信息都会创建新连接的长轮询不同,SSE 会重复使用相同的连接,从而减少开销,进而减少延迟。
SSE API 可在所有现代浏览器中使用,它具有一些通常必须通过轮询才能实现的功能,包括自动重新连接。SSE 与事件流协议协同工作,可以从最后一条已知消息恢复消息流,即使客户端暂时断开连接,也能实现无缝的实时体验。
与长轮询相比,SSE 效率更高,而且内置自动重新连接功能。这是否就是完美的解决方案?与任何在 React 中实现实时更新的方法一样,您也需要注意一些注意事项:
- 使用 SSE,消息通过同一连接从服务器单向流到客户端。这对于通知或新图表数据等实时更新来说很好,但对于信息必须通过同一通道双向流动的游戏或聊天来说,它可能不是最合适的选择。
- 与长轮询类似,每个客户端都会打开与服务器的长期连接,从而占用临时端口、内存和带宽等资源。
- 随着应用程序的扩展,您需要增强服务器或将传入连接分散到多个主机上。然而,由于连接是有状态的,因此与普通 HTTP 请求相比,这将需要一种独特的方法。
- 例如,轮询和 SSE 都不支持在线状态,因此很难在聊天应用程序或团队协作应用程序中显示谁在线。
建议:SSE 是比轮询更好的选择,特别适合单向更新,例如通知或实时源。该 API 受益于广泛的浏览器支持,甚至包括您必须自己实现的便捷功能。缺点是信息只能通过连接从服务器单向流动到客户端,这可能不适合多人协作、聊天或游戏等信息必须双向流动(可能是并行)的情况。虽然您可以通过单独的通道将更新从客户端发送到服务器,但这会增加后端将传入消息链接到其传出连接的复杂性。
WebSockets
WebSocket是一种支持应用程序之间双向通信的通信协议。
当需要双向通信(例如聊天和多人协作)时,它们是一个不错的选择。
此外,当您需要在可用时立即从服务器推送新数据时,WebSocket 非常适合 – 例如实时体育比分更新、包裹递送位置更新或实时图表数据。
由于它们是全双工的,因此信息可以同时在两个方向上流动,这使得 WebSockets 成为高吞吐量场景(例如在线多人游戏)的有吸引力的选择。
- 与继承了 HTTP 优点的轮询或SSE相比,WebSocket 是一种完全自定义的协议。它们无法与您现有的 HTTP 代理一起使用,因为 WebSocket 不是 HTTP,这意味着您需要自己实现压缩等功能。一般来说,为了在生产中实现可靠的实时更新,通常需要做很多工作。
- 尽管 WebSocket 受益于广泛的浏览器支持,但在不支持 WebSocket 的环境中(例如具有严格防火墙的医院),有时需要使用 SSE 或长轮询等后备选项。这可能涉及双倍的实施工作,以及双倍的扩展复杂性,因为每种方法的方法根本不同。
- WebSockets 确保消息按照发送的顺序传递,这通常被认为是一个优点。除此之外,这也意味着 WebSocket 容易受到队头 (HOL) 阻塞的影响。这是一种经过深思熟虑的权衡,适用于大多数项目,但在某些情况下,您可能希望实现尽可能高的吞吐量和最低的延迟,即使这意味着消息有时会乱序到达(或根本不到达)。
建议:WebSocket 是专门为实时更新而构建的,而且用途非常广泛。无论您需要单向更新、双向更新还是两者都需要,WebSocket 都是面向未来的选择。缺点是,您需要花费比您可能希望的更多的时间来重新发明通过 HTTP 免费获得的功能,例如压缩和错误处理。与长轮询或 SSE 不同,它们的状态性质使它们难以扩展。
WebTransport
WebTransport 是一种实验性网络 API,可实现客户端与 HTTP/3 服务器之间的双向通信。
它通过数据流和数据报分别支持可靠和不可靠的数据传输。它还提供低延迟、高吞吐量和无序传输功能。
通过基于 HTTP/3 和 QUIC 协议,WebTransport 避免了 WebSockets 所遇到的线头阻塞延迟问题,而且在创建连接时效率更高,从而可能减少延迟。
与此同时,由于该技术尚未完全定义,浏览器还缺乏支持,而且这种支持还将持续一段时间。
建议 WebTransport 仍是一项试验性功能,其规范和实施在未来可能会发生变化。不过,这是一项令人兴奋的技术,有望改善网络通信体验。虽然它们可能适合受众有限的辅助项目或生产应用程序,但对大多数项目来说还为时过早。
如何使用 React 实现实时更新
要在 React 中实现实时更新,您基本上别无选择!
轮询提供了一种通过 HTTP 定期获取更新的直接方法,而 SSE、WebSockets 和 WebTransport(如果您觉得这些技术很 “前沿 “的话)等专用技术则可以让服务器在准备就绪后立即推送新信息。
推送比轮询更有效率,但由于需要保持连接开放,因此它们的扩展非常困难。
事实上,这些方法都不是 React 特有的。它们都基于 JavaScript 浏览器 API,如 fetch、WebSockets 和 EventSource (SSE)。也就是说,在 React 中使用这些方法中的任何一种,都需要考虑打开连接的最佳位置、如何管理和清理连接,以及如何确保需要实时数据更新的组件能够访问这些更新,从而在不造成多余渲染的情况下呈现 UI 更新。
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/im/38082.html