如何在 sharedworkers 中使用 html5 websockets

Posted

技术标签:

【中文标题】如何在 sharedworkers 中使用 html5 websockets【英文标题】:How to use html5 websockets within sharedworkers 【发布时间】:2021-06-22 09:43:30 【问题描述】:

在查看 *** 上的类似问题后,我没有发现任何对我想要在我的项目中做的事情有多大帮助。阅读和研究我成功地使应用程序与我的 Ratchet php websocket 服务器建立了多个连接,但我注意到每次用户重新加载页面或在新选项卡中打开链接时,客户端 websocket 都会断开连接,然后再次重新连接。

所以,我想知道如何在使用 Sharedworker 的 Web 应用程序中为多个用户只获得一个到 WebSocket 服务器的持久连接。

我在客户端是这样的:

<script>
$(document).ready(function($) 
   let socket = new WebSocket("ws://realtime:8090");

   socket.onopen = function(e) 
      console.log("Browser client connected to websocket server");
      socket.send("Greetings from the browser!");
   ;

   socket.onmessage = function(event) 
      console.log('Data received from server: ' + event.data);
   ;

   socket.onclose = function(event) 
      if (event.wasClean) 
         console.log(`Connection closed cleanly, code=$event.code reason=$event.reason`);
      
      else 
         // e.g. server process killed or network down
         // event.code is usually 1006 in this case
         console.log('Connection closed unexpectedly.');
      
   ;

   socket.onerror = function(error) 
      alert(error.message);
   ;     
);
</script>

【问题讨论】:

【参考方案1】:

好的,在阅读、研究和尝试不同的东西和代码示例之后,我得出了这个解决方案:

客户端(浏览器)应该与 Sharedworker 建立连接。 sharedworker 是一个单独的 javascript 文件,其中包含 sharedworker 的核心以及需要在其中执行的任何其他 JS 代码。 我首先测试了 sharedworker 在浏览器选项卡上的正常工作,计算每个用户打开的选项卡的数量,并将消息共享给一个用户,然后共享给一组用户。 一旦浏览器和 Sharedworker 之间的通信通过了这些测试,我就将 websocket 代码添加到 Sharedworker JS 文件的正文中。

最后,客户端(浏览器)是这样的:

  <script>
   $(document).ready(function($) 
      var currentUser = " Auth::user()->name ";

      let worker = new SharedWorker('worker.js');
      worker.port.start();
      worker.port.postMessage(
         action: 'connect',
         username: currentUser
      );

      worker.port.onmessage = function(message) 
         console.log(message.data);
      ;

   );
  </script>

Sharedworker 如下所示:

// All this code is executed only once, until the onconnect() function.
//---------------------------------------------------------------------

// The array AllPorts contains objects with the format user:<string>, port:<MessagePort>
let AllPorts = [];

var socket = new WebSocket("ws://ssa:8090");

// Called when the WebSocket Server accepts the connection.
socket.onopen = function(e) 
   //
;

// Event handler fired when the WebSocket Server sends a message to this client.
socket.onmessage = function(e) 
   var message = JSON.parse(e.data);
   // This loop sends a message to each tab opened by the given user.
   for (var i = 0; i < AllPorts.length; i++) 
      if (AllPorts[i].user == message.to) 
         AllPorts[i].port.postMessage(message.msg);
      
   
;

socket.onclose = function(event) 
   if (event.wasClean) 
      console.log('Connection closed normally');
   
   else 
      console.log('Connection closed unexpectedly.');
   
;

socket.onerror = function(error) 
   console.log(error.message);
;



// This event handler is fired every time a new tab is opened on the web browser.
onconnect = function(ev) 
   let port = ev.ports[0];

   port.onmessage = function(e) 
      console.log(e.data.action);
      let currentUser = e.data.username;
      let userIsConnected = false;

      switch (e.data.action) 
         case "connect":
            for (var i = 0; i < AllPorts.length; i++) 
               if (AllPorts[i].user == currentUser) 
                  userIsConnected = true;
               
            
            // Add new connected tab to AllPorts array.
            AllPorts.push(user: currentUser, port: port);
            if (!userIsConnected) 
               // New users are added to the list of the WebSocket Server.
               setTimeout(() => 
                  socket.send(JSON.stringify(action: 'connect', username: currentUser));
               , 600);
            
            break;

         case "close":
            console.log(AllPorts);
            var index;
            // This is also executed when the user reloads the Tab.
            for (var i = 0; i < AllPorts.length; i++) 
               if (AllPorts[i].port == port) 
                  index = i;
                  currentUser = AllPorts[i].user;
               
            
            AllPorts.splice(index, 1);
            userIsConnected = false;
            // Check for any connected tab.
            for (var i = 0; i < AllPorts.length; i++) 
               if (AllPorts[i].user == currentUser) 
                  userIsConnected = true;
               
            
            if (!userIsConnected) 
               // User doen't have more tabs opened. Remove user from WebSocket Server.
               socket.send(JSON.stringify(action: 'disconnect', username: currentUser));
            
            break;

         case "notify":
            // Check if given user is connected.
            for (var i = 0; i < AllPorts.length; i++) 
               if (AllPorts[i].user == currentUser) 
                  userIsConnected = true;
               
            
            if (userIsConnected) 
               socket.send(JSON.stringify(action: 'notify', to: currentUser, message: e.data.message));
            
       // switch
    // port.onmessage
 // onconnect

【讨论】:

以上是关于如何在 sharedworkers 中使用 html5 websockets的主要内容,如果未能解决你的问题,请参考以下文章

如何与 SharedWorker 共享数据

Deno Web Worker API - SharedWorker

Javascript SharedWorkers 演示到 Typescript 演示问题

Web Worker是什么

如何将htm文档中的表格数据转换为Excel工作表

如何使用win32com将.htm添加到电子邮件正文