4

I've got a problem with IE10 that I can duplicate readily. After bouncing around in my app through a few pages, IE entirely locks up (no "long running script" warning, just entirely frozen). I have to kill it from the Task Manager. I've disabled all add-ons and have a clean slate. I'm running on a sizeable workstation (Win7, 16GB ram, i7, yadda yadda).

It doesn't freeze in Chrome or Firefox. Only IE10 and IE11.

About my app

I'm integrating with an industrial control system to show the active status of my system. I have a lot of XHR polling going on (will be moving to WebSocket, but for now, this is easy to integrate with my API). Refreshing data from an endpoint every 500ms, which updates a bunch of fields on the page.

When the app isn't frozen, it's nice and snappy to navigate through. Can't find any specific condition that causes the freeze.

At any given time, my app has between 75 and 400 $watches (counted using this answer).

Currently running AngularJS v1.3.0-rc.4. Had similar lockups on 1.2.25.

So, my question

How do I even go about debugging this? I've tried leaving F12 Developer Tools open, and nothing gets outputted to the console. Running script profiler (Batarang not available in IE) shows that I spend about 200ms (inclusive) every 10s in the $digest. What do I try next?

Community
  • 1
  • 1
Mike Griffith
  • 1,201
  • 11
  • 17
  • Maybe Visual Studio's profiler is better: http://msdn.microsoft.com/en-us/library/dd264908.aspx – Sergiu Paraschiv Oct 07 '14 at 14:46
  • if you're polling every 500ms, where is that $interval setup/initialized controller or service/factory? (I know this isn't directly debug related, just a thought) – Brocco Oct 07 '14 at 14:50
  • @Brocco It's in a polling Service included by the Controller. (I just $timeout rather than $interval so I make sure to keep a minimum 500ms spacing between processing response and starting next request). – Mike Griffith Oct 07 '14 at 15:38
  • @MikeGriffith Understood, since a new controller gets created every time I was going to suggest stopping the polling on the destruction of the controller. – Brocco Oct 07 '14 at 16:20
  • @Brocco Yep, already make sure to do that (tie into the $scope $destroy event to "unregister" from polling). Thanks for the idea. My network activity looks completely reasonable, until IE freezes (at which point all XHR activity stops hitting the server). – Mike Griffith Oct 07 '14 at 16:54
  • @MikeGriffith IE struggles with dynamic DOM, angular does tries to minimize changes by using the `track by` option on `ngRepeat` so if you're not using that I'd suggest adding that to any lists you have. – Brocco Oct 07 '14 at 17:18
  • @MikeGriffith How's it been going? Any luck so far? –  Oct 16 '14 at 16:37

2 Answers2

4

Ouch, I can empathize.

Can you separate the concerns? Test your frontend (the DOM portion with ng-repeat) with a mock of your service that doesn't use XHR, and see if you run into the same issue. You can also try testing the XHR service without hooking it to your frontend. (For instance, you could have a test view that only has something like <span>{{myDataArray}}</span>, to avoid the ng-repeat issue, for testing purposes.) Basically, try to split the issue in half and see if you can still duplicate the problem.

Basically, my reasoning is this; if you mock your service and still poll every 500ms, and you run into the problem, you may have an issue with IE's DOM updates. If you don't run into the problem, but you test the real service and IE freezes, then there's a problem with XHR somewhere (perhaps your polling time?) or perhaps an issue with Angular's watch system.

I wish I could be of more help here, but this is where I'd start. Attempt to narrow down the problem by culling some code. It won't be fun, but if you've written your application using Angular's best practices (namely, dependency injection and separation of concerns) it'll be less painful.

TL;DR - "What do I try next?" You're going to have to start intelligently culling some code to see what works and what doesn't.

  • I've continued to try this, and it does appear to be the DOM giving the most trouble. As such, I've removed all ng-repeats in favor of hand-crafted DOM manipulation (with debouncing for IE to avoid touching it as often as I can in Chrome). So, still not perfect, but thanks for the tip! – Mike Griffith Oct 16 '14 at 18:28
  • @MikeGriffith For what it's worth, I completely forgot to mention this - but when you use `ng-repeat`, it's often good to use the `track by` statement. This theoretically avoids a lot of unnecessary DOM repaints (although in practice, I don't know how much of a gain it is after a certain threshold). The real issue is the DOM and the digest cycle, as `ng-repeat` uses a lot of watches as I understand it (in addition to the interpolation stuff). –  Oct 16 '14 at 20:24
1

My global solution for all IE Lock Ups (pun intened) is to wrap the problematic code inside window.setTimeout. Now majority of these problems are caused either by:

  1. Loading too many DOM elements

  2. Processing a set of DOM elements many many times especially if you have multiple watchers.

How to tackle this: Use Google Debugging Profiling Tools (especially heap snapshots) to keep track of your DOM elements. It is actually really great.

It is highly possible you are loading too much unnecessary DOM elements. Try to lazy load them by using some flags on the scope objects.

For example, we needed to show a tree of items for user to select and we were loading all of them up front which counted to several hundred thousands. That crippled IE and slowed down Chrome. What I did was to only load the top categories and only load the children only if a category was expanded. Look for some optimizations like that.

These kind of problems don't show themselves in development databases with a few thousand records in them. They only show up in production databases and in launch date so take your time to go through your document structure and find the risk points.

You can also use the Chrome Debugger's AnugularJS tab (the performance section). It is a great tool and shows the watchers in DOM elements. Take a look.

Blazemonger
  • 90,923
  • 26
  • 142
  • 180
Aidin
  • 2,134
  • 22
  • 26