Terrible performance issues with websocket - every message triggering Angular change detection

Viewed 2090

I've got a websocket and I'm currently streaming messages at about 45 per second. At this level it completely kills chrome. All functionality in the browser window is locked up.

I've cut back my implementation to try find the root cause of this issue, suspecting it could have been some problem with how I'm processing these messages - or updating/change detection in Angular.

But now I'm left with the simplest websocket implementation I can get:

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);
  }
};

This is in an Angular Injectable, but it's not interacting with anything.

It writes to the console every 100 messages. This still kills the browser with 100% CPU usage, it doesn't even output to the console most of the time until I stop the message stream, then everything catches up and it squirts a few lines of "recieved x00" messages.

The messages themselves are JSON, and look like this:

{
  "Topic":"2a736d15-a2fe-43b2-8e8b-ee888f15a53a","Type":1,
  "Message": {
     "Value":2,
     "Timestamp":"2017-06-05T14:46:21.615062+01:00"
   }
}

They're typically about 126 characters.

I'd assumed websockets can handle tens of thousands of messages per second, but I can't find any sensible metrics on google, does this sound like unreasonable performance?

I've also checked in the CPU profiler. When everthing's locked out, it's just a big wall of calls, so I turned it down to a single message a second:

enter image description here

Drilled down into one of these spikes (happens for every single message!):enter image description here

I threw a break point in one of these locations, and it appears that Angular is doing something whenever the websocket gets triggered, and it's something to do with Zones (something I have zero experience in!):

The first thing in the stack is a ZoneTask.invoke on the Websocket itself, but then NgZone gets triggered, and ultimately a very expensive change/update chain is called:

enter image description here

How could all this be happening? The 7 lines of code subscribing to the websocket are completely independent from Angular's change detection right? They're not changing any values that are bound to any components. Their only link is they are sitting in a method inside an @Injectable()

1 Answers
Related