websocket 的严重性能问题 - 每条消息都会触发 Angular 更改检测
Posted
技术标签:
【中文标题】websocket 的严重性能问题 - 每条消息都会触发 Angular 更改检测【英文标题】:Terrible performance issues with websocket - every message triggering Angular change detection 【发布时间】:2017-06-05 14:24:06 【问题描述】:我有一个 websocket,我目前正在以大约每秒 45 条的速度流式传输消息。在这个级别上,它完全杀死了铬。浏览器窗口中的所有功能都已锁定。
我已经缩减了我的实现,试图找出这个问题的根本原因,我怀疑这可能是我处理这些消息的方式存在问题 - 或者在 Angular 中更新/更改检测。
但现在我只剩下我能得到的最简单的 websocket 实现了:
this.socket = new WebSocket('ws://localhost:5000/ws');
let i = 0;
this.socket.onmessage = (e: MessageEvent) =>
i++;
if (i % 100 === 0)
console.log('recieved' + i);
;
这是一个 Angular Injectable,但它不与任何东西交互。
它每 100 条消息写入控制台。这仍然会以 100% 的 CPU 使用率杀死浏览器,在我停止消息流之前,它甚至大部分时间都不会输出到控制台,然后一切都赶上了,它会喷出几行“received x00”消息。
消息本身是 JSON,如下所示:
"Topic":"2a736d15-a2fe-43b2-8e8b-ee888f15a53a","Type":1,
"Message":
"Value":2,
"Timestamp":"2017-06-05T14:46:21.615062+01:00"
它们通常约为 126 个字符。
我假设 websockets 每秒可以处理数万条消息,但我在 google 上找不到任何合理的指标,这听起来像不合理的性能吗?
我还检查了 CPU 分析器。当一切都被锁定时,它只是一堵巨大的电话墙,所以我把它降低为每秒一条消息:
深入研究其中一个尖峰(每条消息都会发生!):
我在其中一个位置设置了一个断点,每当 websocket 被触发时,Angular 似乎都在做某事,这与区域有关(我对此的经验为零!):
堆栈中的第一件事是 Websocket 本身的 ZoneTask.invoke,但随后 NgZone 被触发,最终调用了一个非常昂贵的更改/更新链:
这一切怎么会发生?订阅 websocket 的 7 行代码完全独立于 Angular 的变更检测,对吧?它们不会更改绑定到任何组件的任何值。他们唯一的链接是他们坐在@Injectable()
内的方法中
【问题讨论】:
看这篇文章并使用 WebWorkers/ServiceWorkers 进行研究:***.com/questions/17998011/… 【参考方案1】:Sods 法律,只要我发布一个问题,我就会找到答案。通常我会删除它,但我找不到太多关于该主题的内容,因此它可能对某人有用。
这是 Zones 的问题。这是useful blog post。一般来说,Angular 2 使用区域来驱动它的变更检测:
Angular 2 使用 zone.js 的原因是要知道我们的处理程序何时完成,然后 NgZone 服务(NgZone 是一个包装区域服务的类)调用 ApplicationRef.tick() 方法。 tick() 方法从上到下扫描树组件,并在每个组件中计算模板中存在的表达式。如果表达式的结果不等于前一个结果,(从前一个刻度)Angular 将更新连接到这个表达式的 DOM 属性。
一个简单的单独获得消息性能的简单解决方案是在区域外运行,从而使用方便的方法runOutsideAngular
进行 Angular 的更改检测:
this.zone.runOutsideAngular(() =>
let i = 0;
this.socket.onmessage = (e: MessageEvent) =>
i++;
if (i % 100 === 0)
console.log('recieved' + i);
;
);
【讨论】:
以上是关于websocket 的严重性能问题 - 每条消息都会触发 Angular 更改检测的主要内容,如果未能解决你的问题,请参考以下文章