当浏览器选项卡没有焦点时使用 Websocket 进行角冻结

Posted

技术标签:

【中文标题】当浏览器选项卡没有焦点时使用 Websocket 进行角冻结【英文标题】:Angular Freezing With Websocket When Browser Tab Doesn't Have Focus 【发布时间】:2020-09-02 08:47:31 【问题描述】:

我们有一个 Angular 8 项目,它有一个带有恒定数据流的 websocket。数据存储在 clientInfo 对象中,更改会立即通过 service.clientInfo.variable 反映在页面中。唯一的问题是,当我转到浏览器中的另一个选项卡并返回该页面时,有时页面需要几秒钟才能赶上,并且在那之前一切都没有响应。

如果我让浏览器选项卡长时间处于非活动状态,我的所有组件都将被隐藏,整个选项卡将永久冻结,我必须重新打开它(chrome)。我注意到,如果我转到网站的另一部分没有显示来自 websocket 的数据,则不会发生这种情况。对我来说,这似乎是更改检测正在缓冲所有内容,并且在浏览器选项卡没有焦点时不进行任何 DOM 更改,最终耗尽内存。

我想我可以尝试使用文档的“visibilitychange”事件来检测浏览器选项卡何时被隐藏,然后设置一个显示/隐藏布尔值。我试图使用一个标志使用* ngif来隐藏显示WebSocket数据的部分,但是当标签丢失焦点时,NGIF不会及时隐藏它。

有什么简单的解决方案吗?我可以在某种程度上告诉Angular在Tab禁止处于活动状态时停止在ClientInfo对象上的更改检测吗?我以为我可以使用前面提到的可见性标志来将传入的WebSocket数据存储在不同的对象中,然后当标签重新归焦时,我可以将这些值与主要的ClientInfo对象合并,但我确定必须有更简单的解决方案。

编辑以更清楚地了解其设置方式:

这是我们服务中的 clientInfo 对象的简化版本,还有更多内容,但流是相关页面上显示的部分:

clientInfo = 
  streams: [
     id: 1, count: 123 ,
     id: 2, count: 456 
  ]
;

然后页面会显示此数据(再次简化),如下所示:

<li *ngFor="let stream of service.streams">
   stream.count 
</li>

streams 值是我们服务中的一个 getter,设置如下:

get streams(): DataStream[] 
  if(this.clientInfo) 
    return this.clientInfo.streams;
  
  return [];

我们使用getter的原因是因为路径实际上比clientInfo.streams长,为了简单起见我只是这样写。

websocket 发送增量更新,因此我们遍历流,检查 id 是否匹配,并更新计数。

提前致谢, 克里斯。

【问题讨论】:

您的场景有点不清楚,最好附上一段代码来解释您面临的问题。至于在浏览器选项卡切换或失去焦点时执行操作,您可以使用 @HostListener('blur', ['$event']) 【参考方案1】:

抱歉,我想我的问题过于简化了。我省略了在 ngFor 循环中使用的 ngx-charts (https://github.com/swimlane/ngx-charts) 组件。当我在 clientInfo 对象中注释掉更新图形数据的代码时,页面停止冻结。

ngx-charts 一定一直在要求 d3 一遍又一遍地更新图表,但标签没有被聚焦。没有多少人会这样做,但我想要点是,当没人能看到你的标签时不要更新 ngx-charts。

【讨论】:

以上是关于当浏览器选项卡没有焦点时使用 Websocket 进行角冻结的主要内容,如果未能解决你的问题,请参考以下文章

检测浏览器选项卡是不是有焦点

当用户关闭浏览器或选项卡而不注销时如何将用户标记为离线

辅助功能 - 如何在元素上设置自定义选项卡焦点顺序

在选项卡和焦点轮廓未显示时跳过第一个导航锚

选项卡不在焦点时的 Firebase 通知

即使选项卡不在焦点上,也从 Web 应用程序发送地理位置?