在我的一个脚本上,我有以下代码:
var webSocket = window.WebSocket || window.MozWebSocket;
window.ws = new webSocket('ws://64.121.210.140:2585/consoleappsample', 'my-protocol');
哪个工作正常。但是,当用户更改页面时,我必须重新建立连接。我相信这会导致我的代码出现问题,因为如果客户端将数据发送到服务器然后更改页面,则可能无法接收数据并且正在发生竞争条件。
我试图将window.ws
置于全球范围内,但它似乎没有解决问题。有没有办法让 WebSockets 连接在页面之间持久化,这样就不需要不断重新建立连接?
您提到的全局范围始终与 JavaScript 上下文相关,并且为每个窗口创建一个上下文(并在从内存中卸载文档时销毁)。因此,您的努力是无用的:如果用户更改页面,则无法保持连接打开状态。当然,您可以将Web应用程序作为"单页"应用程序,其中所有数据都使用XMLHttpRequest/ajax/WebSocket加载。因此,离开页面意味着离开/关闭应用程序,并且关闭套接字是有意义的。
另一种旧方法是将页面放在框架中,用户仅在框架中导航(即使它占用窗口的整个大小)。这样,您可以在最顶部的窗口中创建WebSocket,该窗口永远不会更改(这也意味着地址栏中显示的URL将始终相同)。
话虽如此,我同意@dystroy:您的应用程序应该始终能够处理这种情况 - 用户可能会遇到一些网络问题并暂时失去连接,即使它没有离开页面。
您可以尝试在共享 WebWorker 中创建 WebSocket 连接,该连接允许来自同一域的多个页面共享执行上下文。但是,目前尚不清楚共享工作线程是否在页面重新加载或替换中持续存在:共享 Web 辅助角色是否在单个页面重新加载中持续存在,链接导航
此外,Shared WebWorkers目前对浏览器的支持有限(webkit和Opera)。
更新:
由于单个共享 Web worker 可以提供多个页面,因此实现比普通 Web Worker 稍微复杂一些。
下面是一个共享的 Web worker 示例,它使用 WebSocket 并且可以在
首先是 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>
在shared.js
中实现共享工作的Javascript:
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);
我已经验证了这在 Chrome 52 中有效。
不幸的是,无需在 SPA 应用程序中更改站点的最干净解决方案仅使用一个 ServiceWorker 即可获得,因为它在后台完成工作(也关闭了选项卡),并且还解决了多个选项卡的问题。我说"不幸的是",因为它们仍然与大多数浏览器不兼容。
我自己找到的唯一解决方案是在服务器端对套接字通道进行分组,并创建一个队列以保存因更改页面而丢失的消息。在这种情况下,您有某种虚拟通道。
您可以在本地存储中记录与 websocket 服务器的对话,该对话在页面加载后持续存在。