Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Slow ng-repeat because of AnimateRunner even without ngAnimate #14066

Closed
ArekSredzki opened this issue Feb 17, 2016 · 15 comments
Closed

Slow ng-repeat because of AnimateRunner even without ngAnimate #14066

ArekSredzki opened this issue Feb 17, 2016 · 15 comments

Comments

@ArekSredzki
Copy link

I'm trying to print a lot of elements to the DOM, but it is painfully slow.
However, the reason is caused by AnimateRunner and nothing else.

Note: I do not want to filter the elements further, but rather get to the bottom of why an un-needed component is stalling the entire browser

I have disabled ngAnimate, the page has no animations, yet the slowest part of the whole process is it's complete function.

Please see the profile below

Your suggestions are greatly appreciated.

@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

Which version of Angular is this?

@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

Why does this function exist?
the core ng module has its own implementation of the $animate service. So even when ngAnimate isn't included the functions that are called are the same: $animate.enter etc, but of course the amount of work that is done is much less. When ngAnimate is included, it overwrites these functions and adds the actual animation logic.
The runner is needed because even when ngAnimate isn't included we need to make sure that animation event listeners are executed correctly. So a certain subset of logic (the animate queue and the runner) exists in the ng module, too.
There's probably potential to make these faster, but that is the status quo. You are very welcome to see if there are improvments to be made.
That said. ngRepeat was never lightning fast and I assume with many elements (how many do you try to render?) it will always be slow.

@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

The profile also doesn't really show that the slowness is "caused by AnimateRunner and nothing else."

@frfancha
Copy link

Why animation event listeners must be run when ngAnimate is not included?

@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

The event listeners / callbacks should fire even when no actual animations run. This can be important for example if you are testing your application without animations. Then you would still want the resilts of the callbacks that fire when the animation is complete.

@ArekSredzki
Copy link
Author

@Narretz
Thank you for the prompt response.

This is with version 1.5, running in an electron browser window (chromium).

I will complete more meaningful testing once I get into the office later today.

@frfancha
Copy link

@Narretz Thanks for the explanation.
However I still don't understand (sorry for my slowness ;-) ).
If the goal is only to enable testing animations without including ngAnimate, then why is it always (and not on demand) enabled and why should we always pay the performance penalty (including in production) when we don't intend to use ngAnimate at all?

@gkalpak
Copy link
Member

gkalpak commented Feb 17, 2016

@Narretz, do we really need the RAFs without ngAnimate included ?

@ArekSredzki
Copy link
Author

The large majority of the computation time is spent checking whether the element should have animations applied to it. Unfortunately this occurs even if we don't have any animations... I'll try to make some improvements.

@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

The large majority of the computation time is spent checking whether the element should have animations applied to it. Unfortunately this occurs even if we don't have any animations... I'll try to make some improvements.

Can you elaborate? Which code does that? Please be specific if you mean the code with the ngAnimate module as a dependency or without it.

@gkalpak I'm not sure if the rAF is needed, but it definitely enforces asyncronicity, which is possibly what we want for consistency.

@frfancha Different example: you are using a 3rd party module that uses $animate and also an animation callback that is important. If you are now disabling ngAnimate from your app you would expect the DOM operations and the callback to work as before.

@ArekSredzki
Copy link
Author

@Narretz After some further investigation I've identified the issue with a high count of redundant calls to retrieve the window.document object.

It is especially noticeable when using angular in electron because electron will make a quick ipc call to it's main thread to retrieve whether the document is hidden. This call is quick, but synchronous as it's integrated to getting the window.document object, and slows everything to a halt in volume.

One might argue that this is an issue with electron, but I would disagree.
In the very large majority of cases the document is not hidden and this code is a blocker in many of angular's operations (ex. ngSwitchWatchAction, $watchCollectionAction, ngIfWatchAction). Plus, it's likely that other frameworks make use of similar get implementations.

TL;DR it is unnecessary to make calls for document.window thousands of times in the span of a second for the rare case when the document is hidden.

Stats
Using current AnimateRunner._tick: 2510ms
_tick which just calls rafTick(fn): 650ms

Interested to hear your thoughts on how the redundant calls should be avoided.

@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

@ArekSredzki and I'm interested in your thoughts :) Thanks for investigating. We could maybe cache the hidden value, but the question is in which time period. Another option would be to listen to the events that are emitted when a document is hidden or shown.

@ArekSredzki
Copy link
Author

@Narretz Thanks :)
I was originally thinking of caching it for 2 seconds or so (there shouldn't be any real detriments in that time... but I hadn't realized that there's an event for that. Good idea, lets do that.

https://developer.mozilla.org/en-US/docs/Web/Events/visibilitychange is exactly what we need.

I'm not familiar with angular's inner workings, does it have a stateful module where we could keep this value?

@Narretz Narretz self-assigned this Feb 17, 2016
@Narretz
Copy link
Contributor

Narretz commented Feb 17, 2016

We can keep it in a provider. I'm working on a Pr.

@ArekSredzki
Copy link
Author

@Narretz Great! Excited to check it out once it's ready.

Narretz added a commit to Narretz/angular.js that referenced this issue Feb 17, 2016
Accessing the document for the hidden state is costly for
platforms like Electron.

Closes angular#14066
Narretz added a commit to Narretz/angular.js that referenced this issue Feb 21, 2016
Accessing the document for the hidden state is costly for
platforms like Electron.

Closes angular#14066
Narretz added a commit to Narretz/angular.js that referenced this issue Feb 21, 2016
Accessing the document for the hidden state is costly for
platforms like Electron.

Closes angular#14066
Narretz added a commit to Narretz/angular.js that referenced this issue Apr 26, 2016
Accessing the document for the hidden state is costly for
platforms like Electron.

Closes angular#14066
Narretz added a commit that referenced this issue Apr 26, 2016
perf(ngAnimate): listen for document visibility changes

Accessing the document for the hidden state is costly for
platforms like Electron. Instead, listen for visibilitychange
and store the state.

(#14071)
Closes #14066
Narretz added a commit to Narretz/angular.js that referenced this issue Apr 26, 2016
perf(ngAnimate): listen for document visibility changes

Accessing the document for the hidden state is costly for
platforms like Electron. Instead, listen for visibilitychange
and store the state.

(angular#14071)
Closes angular#14066
Narretz added a commit to Narretz/angular.js that referenced this issue Apr 26, 2016
perf(ngAnimate): listen for document visibility changes

Accessing the document for the hidden state is costly for
platforms like Electron. Instead, listen for visibilitychange
and store the state.

(angular#14071)
Closes angular#14066
Narretz added a commit to Narretz/angular.js that referenced this issue Apr 26, 2016
Accessing the document for the hidden state is costly for
platforms like Electron. Instead, listen for visibilitychange
and store the state.

Closes angular#14066
Narretz added a commit to Narretz/angular.js that referenced this issue May 6, 2016
Accessing the document for the hidden state is costly for
platforms like Electron. Instead, listen for visibilitychange
and store the state.

Closes angular#14066
Narretz added a commit that referenced this issue May 6, 2016
Accessing the document for the hidden state is costly for
platforms like Electron. Instead, listen for visibilitychange
and store the state.

Closes #14066
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants