websocket的可怕性能问题 - 每条消息都会触发Angular变化检测

时间:2017-06-05 14:24:06

标签: angular websocket

我有一个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占用率杀死浏览器,它甚至不会在大多数时间输出到控制台,直到我停止消息流,然后一切都赶上并且它喷出几行"收到的x00& #34;消息。

消息本身是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分析器。当外界被锁定时,它只是一大堆通话,所以我将它一秒钟转为一条消息:

enter image description here

深入研究其中一个峰值(每条消息都会发生!):enter image description here

我在其中一个位置扔了一个断点,看来Angular在触发websocket时正在做某事,而且它与Zones有关(我没有经验!):< / p>

堆栈中的第一件事是Websocket本身的ZoneTask.invoke,但随后NgZone被触发,最终调用了一个非常昂贵的更改/更新链:

enter image description here

这一切怎么可能发生?订阅websocket的7行代码完全独立于Angular的变更检测权限?他们不会更改绑定到任何组件的任何值。他们唯一的联系是他们坐在@Injectable()

内的方法中

1 个答案:

答案 0 :(得分:1)

Sods法律,我一发表问题就找出答案。通常我会删除它,但我找不到关于这个主题的内容,所以它可能对某人有用。

这是Zones的一个问题。这是一个useful blog post。通常,Angular 2使用区域来驱动它的变化检测:

  

Angular 2使用zone.js的原因是知道我们的处理程序何时完成,然后NgZone服务(NgZone是一个包装区域服务的类)调用ApplicationRef.tick()方法。 tick()方法从上到下扫描树组件,并在每个组件中计算模板中存在的表达式。如果表达式的结果不等于先前的结果,(从上一个tick开始)Angular将更新连接到该表达式的DOM属性。

简单地单独获取消息性能的简单解决方案是在区域外运行,因此使用方便的方法runOutsideAngular进行角度变化检测:

this.zone.runOutsideAngular(() => {
  let i = 0;
  this.socket.onmessage = (e: MessageEvent) => {
    i++;
    if (i % 100 === 0) {
      console.log('recieved' + i);
    }
  };
});