未处理的 socket.io 事件会发生啥?

Posted

技术标签:

【中文标题】未处理的 socket.io 事件会发生啥?【英文标题】:What happens with unhandled socket.io events?未处理的 socket.io 事件会发生什么? 【发布时间】:2015-12-25 07:11:27 【问题描述】:

socket.io 会忽略\丢弃它们吗? 我问这个的原因如下。 有一个有几个状态的客户端。每个状态都有自己的一组套接字处理程序。在不同的时刻,服务器通知客户端状态变化,然后发送几个与状态相关的消息。 但!客户端需要一些时间来更改状态并设置新的处理程序。在这种情况下,客户端可能会错过一些消息……因为目前没有处理程序。 如果我理解正确,客户端会丢失未处理的消息。

可能是我错过了这个概念或做错了什么......如何处理这个问题?

【问题讨论】:

【参考方案1】:

未处理的消息将被忽略。这就像当一个事件发生并且该事件没有事件侦听器时一样。套接字接收到 msg 并没有找到它的处理程序,因此没有任何反应。

您可以通过始终安装处理程序然后在处理程序中决定(基于其他状态)是否对消息执行任何操作来避免丢失消息。

【讨论】:

【参考方案2】:

jfriend00 的答案是一个很好的答案,您可能只需将处理程序留在原处并在回调中使用逻辑来根据需要忽略事件。如果您真的想管理未处理的数据包,请继续阅读...

您可以从套接字内部获取回调列表,并使用它与传入的消息头进行比较。这个客户端代码就可以做到这一点。

// Save a copy of the onevent function
socket._onevent = socket.onevent;

// Replace the onevent function with a handler that captures all messages
socket.onevent = function (packet) 
  // Compare the list of callbacks to the incoming event name
  if( !Object.keys(socket._callbacks).map(x => x.substr(1)).includes(packet.data[0]) ) 
    console.log(`WARNING: Unhandled Event: $packet.data`);

  
  socket._onevent.apply(socket, Array.prototype.slice.call(arguments));
;

对象 socket._callbacks 包含回调,键是名称。它们前面有一个 $,因此您可以通过将 substring(1) 映射到它来将其从整个列表中删除。这会产生一个很好的干净的事件名称列表。

重要提示:通常您不应尝试从外部修改任何以下划线开头的对象成员。此外,预计其中的任何数据都是不稳定的。下划线表示它是供该对象、类或函数内部使用的。虽然这个对象不稳定,但它应该是最新的,我们可以使用它,我们不会直接修改它。

事件名称存储在 packet.data 下的第一个条目中。只需检查它是否在列表中,如果不在则发出警报。现在,当您从服务器发送事件时,客户端不知道它会在浏览器控制台中记录它。

现在您需要将未处理的消息保存在缓冲区中,以便在处理程序再次可用时播放。因此,要扩展我们之前的客户端代码...

// Save a copy of the onevent function
socket._onevent = socket.onevent;

// Make buffer and configure buffer timings
socket._packetBuffer = [];
socket._packetBufferWaitTime = 1000; // in milliseconds
socket._packetBufferPopDelay = 50;   // in milliseconds

function isPacketUnhandled(packet) 
  return !Object.keys(socket._callbacks).map(x => x.substr(1)).includes(packet.data[0]);


// Define the function that will process the buffer
socket._packetBufferHandler = function(packet) 
  if( isPacketUnhandled(packet) ) 
    // packet can't be processed yet, restart wait cycle
    socket._packetBuffer.push(packet);
    console.log(`packet handling not completed, retrying`)
    setTimeout(socket._packetBufferHandler, socket._packetBufferWaitTime, socket._packetBuffer.pop());
  
  else 
    // packet can be processed now, start going through buffer
    socket._onevent.apply(socket, Array.prototype.slice.call(arguments));
    if(socket._packetBuffer.length > 0) 
      setTimeout(socket._packetBufferHandler,socket._packetBufferPopDelay(), socket._packetBuffer.pop());
    
    else 
      console.log(`all packets in buffer processed`)
      socket._packetsWaiting = false;
    
  


// Replace the onevent function with a handler that captures all messages
socket.onevent = function (packet) 
  // Compare the list of callbacks to the incoming event name
  if( isPacketUnhandled(packet) ) 
    console.log(`WARNING: Unhandled Event: $packet.data`);
    socket._packetBuffer.push(packet);
    if(!socket._packetsWaiting) 
      socket._packetsWaiting = true;
      setTimeout(socket._packetBufferHandler, socket._packetBufferWaitTime, socket._packetBuffer.pop());
    
  
  socket._onevent.apply(socket, Array.prototype.slice.call(arguments));
;

在这里,未处理的数据包被推入缓冲区并设置计时器运行。一旦给定的时间过去了,if 开始检查每个项目的处理程序是否准备好。每一个都被处理,直到全部用完或缺少一个处理程序,这会触发另一个等待。

这可以并且将会堆积未处理的调用,直到您耗尽客户端分配的内存,因此请确保这些处理程序确实在合理的时间跨度内加载。并且注意不要发送任何永远不会被处理的东西,因为它会一直尝试。

我用很长的字符串对其进行了测试,它能够推动它们通过,所以他们所说的“数据包”可能不是标准数据包。

在 Chrome 上使用 SocketIO 2.2.0 版进行测试。

【讨论】:

以上是关于未处理的 socket.io 事件会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

Web Socket & Socket.io

如何检测未注册的socket.io事件?

用 Python flask_socketio 反应 socket.io-client 不处理事件

socket.io 连接事件未在 Firefox 中触发

Socket.io 客户端未收到事件

当事件触发并尝试在不再存在的对象中执行事件处理程序时会发生啥?