Javascript 如何维护页面之间的 WebSockets 连接?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10886910/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 03:25:56  来源:igfitidea点击:

How to maintain a WebSockets connection between pages?

javascripthtmlwebsocket

提问by Ryan Peschel

On one of my scripts I have this code:

在我的一个脚本中,我有以下代码:

var webSocket = window.WebSocket || window.MozWebSocket;
window.ws = new webSocket('ws://64.121.210.140:2585/consoleappsample', 'my-protocol');

Which works fine. However, when the user changes pages, I have to re-establish the connection. I believe this is causing problems in my code because if the client sends data to the server and then changes pages, the data may not be received and race conditions are occurring.

哪个工作正常。但是,当用户更改页面时,我必须重新建立连接。我相信这会导致我的代码出现问题,因为如果客户端将数据发送到服务器然后更改页面,则可能无法接收到数据并且会发生竞争条件。

I tried to put the window.wsin global scope but it didn't seem to fix the problem. Is there any way for the WebSockets connection to persist between pages so the connection does not need to be constantly reestablished?

我试图将 放在window.ws全局范围内,但它似乎没有解决问题。有什么方法可以让 WebSockets 连接在页面之间保持不变,因此不需要不断重新建立连接?

采纳答案by ZER0

The global scope you mentioned is always related to the JavaScript Context, and a Context is created for each windows (and destroyed when the document is unloaded from the memory). Therefore, your effort are useless: you can't keep a connection opened if the user change page. Of course you can have your webapp as "single page" application, where all the data are loaded using XMLHttpRequest / ajax / WebSocket. So, leaving the page means leaving / shutdown the application, and makes sense close the socket.

你提到的全局作用域总是和 JavaScript Context 相关的,并且为每个窗口创建一个 Context(并且在从内存中卸载文档时销毁)。因此,您的努力是无用的:如果用户更改页面,您将无法保持连接打开。当然,您可以将您的 web 应用程序作为“单页”应用程序,使用 XMLHttpRequest/ajax/WebSocket 加载所有数据。因此,离开页面意味着离开/关闭应用程序,并且关闭套接字是有意义的。

Another old approach could be put your pages in a frame, where the user navigate only in the frame (even if it takes the whole size of the window). In that way, you can create your WebSocket in the top most window, that is never changed (that also means the URL showed in the location bar will be always the same).

另一种旧方法可能是将您的页面放在框架中,用户仅在框架中导航(即使它占据了整个窗口的大小)。这样,您可以在最顶部的窗口中创建 WebSocket,该窗口永远不会更改(这也意味着地址栏中显示的 URL 将始终相同)。

Said that, I agreed with @dystroy: your application should be always able to handle this scenario - the user could have some network problem and lost the connection for a moment, even if it doesn't leave the page.

这么说,我同意@dystroy:您的应用程序应该始终能够处理这种情况——用户可能会遇到一些网络问题并暂时失去连接,即使它没有离开页面。

回答by kanaka

You could try creating your WebSocket connection in a Shared WebWorker which allows multiple pages from the same domain to share an execution context. However, it's unclear whether Shared Workers persist across a page reload or replace: Do Shared Web Workers persist across a single page reload, link navigation

您可以尝试在 Shared WebWorker 中创建 WebSocket 连接,它允许来自同一域的多个页面共享一个执行上下文。但是,尚不清楚 Shared Workers 是否在页面重新加载或替换时持续存在Do Shared Web Workers persist over a single page reload, link navigation

Also, Shared WebWorkers have limited browser support(webkit and Opera) currently.

此外,共享 WebWorker 目前对浏览器的支持有限(webkit 和 Opera)。

Update:

更新

Since a single shared web worker can serve multiple pages, the implementation is slightly more complicated that normal web workers.

由于单个共享 Web Worker 可以为多个页面提供服务,因此实现比普通 Web Worker 稍微复杂一些。

Here is a shared web worker example that uses WebSockets and can share between

这是一个使用 WebSockets 的共享 Web Worker 示例,可以在它们之间共享

First the HTML:

首先是 HTML:

<!DOCTYPE html>
<html>
<body>
<script>
    var worker = new SharedWorker("shared.js");
    worker.port.addEventListener("message", function(e) {
        console.log("Got message: " + e.data);
    }, false);
    worker.port.start();
    worker.port.postMessage("start");
</script>
</body>
</html>

The Javascript that implements the shared worker in shared.js:

在 中实现共享工作者的 Javascript shared.js

var ws = null
var url = "ws://" + location.hostname + ":6080"
self.addEventListener("connect", function(e) {
    var port = e.ports[0]
    port.addEventListener("message", function(e) {
        if (e.data === "start") {
            if (ws === null) {
                ws = new WebSocket(url);
                port.postMessage("started connection to " + url);
            } else {
                port.postMessage("reusing connection to " + url);
            }
        }
    }, false);
    port.start();
}, false);

I have verified that this works in Chrome 52.

我已经验证这在 Chrome 52 中有效。

回答by Marcello Kad

Unfortunatelly the cleanest solution without changing your site in a SPA application is obtained using just one ServiceWorker because it does the job in background (also with tab closed) and it solve also problems of multiple tabs. I said "unfortunatelly" because they are still not compatible with most of browsers. The only solution i've found by myself consist of grouping socket channels at server side, and create a queue in order to hold the messages lost by changing page. In this case you have kind of virtual channels.

不幸的是,无需在 SPA 应用程序中更改站点的最干净的解决方案是使用一个 ServiceWorker 获得的,因为它在后台完成工作(也关闭选项卡),并且还解决了多个选项卡的问题。我说“不幸的是”,因为它们仍然与大多数浏览器不兼容。我自己找到的唯一解决方案是在服务器端对套接字通道进行分组,并创建一个队列以保存因更改页面而丢失的消息。在这种情况下,您有一种虚拟频道。

回答by Trevor Turton

You could log the conversation with the websocket server in localstorage, which persists across page loads.

您可以在 localstorage 中记录与 websocket 服务器的对话,该对话在页面加载时持续存在。