I encountered performance problems with my AngularJS application on IE and started analyzing the root cause for this. The root cause seems to be, that too many watchers are used, ng-repeat is used for a table with a large amount of data, almost no one-way-data-binding is being used and static data is not being cached. So in general I found out, that it's not just an IE problem.
However, I also started to analyze the digest circle and tried to keep track of it:
$rootScope.$watch(function () {
count += 1;
console.log('Count: ', count);
});
According to my console output, the digest cycle triggers every 1s.
This is very, very problematic in my eyes, because from what I have read so far it should only trigger in certain cases and not continuously. Well, there is a timed request for data, but it's only every 10 seconds...but maybe some change triggers another and so on.
I would like to find out which part of my code triggers the digest cycle, is there a way to do this?
Thanks in advance
Update
The problem was not caused by the view containing the table, I found a hidden
$interval(function () { ... }, 1000)
somewhere else, which causes the digest cycle to trigger every second.
Related
I need to check if an element is appearing after refreshing a page continuously, cause it takes a while for the changes to be reflected and the element to appear in that page.
Is there any built in method in selenium using Ruby as the programming language ?
Just to confirm, it sounds like the page does not dynamically update once the content is available, so you have to wait until that is true, and then manual refresh, right?
I don't know of anything built into selenium to handle this. It feels like it might even be a symptom of a UI that needs a little more design work (pardon my critique). If the user is experiencing the same thing as the test -- kicking off an action, waiting some unspecified period of time, and then manually refreshing to see the results -- that's a kind of lousy user experience. If that's a bad assumption, and there IS feedback (e.g. a spinner), then your best option will be to conditionally wait for the spinner to appear and then disappear, and then refresh a single time.
If there's really no visible feedback, then you still have a couple of options:
Easy: Hardcode a sleep that's longer than the operation will ever take to complete, and refresh once.
Medium: In a loop, sleep for a constant delay, refresh, repeat until some timeout.
Hard: If the delay required varies widely (sometimes seconds, sometimes minutes), you might consider an exponential back off solution, that sleeps for increasingly longer delays each iteration, before ultimately timing out. The upside is that you're not frantically refreshing dozens of times, the downside is that your delay might be unnecessarily long, if the content arrives just after the next big delay begins.
You can use wait method for the element to be available.
If you need to refresh the page continuously just make sure to wait after each refresh.
What is the difference between $evalAsync and $applyAsync? My understanding is that when I use $evalAsync from a directive, the expression will evaluate before the browser renders.
So as an example, if I wanted to scroll to a particular position on a page but not show the jump to that spot, I could use this to scroll to the position and since it fires before the browser has rendered, this visual bug would be gone.
However, what is the purpose of applyAsync? When is it a good idea to use one over the other?
The
$evalAsync()
will execute in the current digest
$applyAsync()
in a scheduled one.
If you need details:
Ben Nadel or stack here
Here is what I have been using $applyAsync for. Basically, I use this as a safe $apply. You know that annoying error when you try to trigger a digest when one is already in progress? If you use $applyAsync, you will get another digest, but it will occur when the current digest cycle has completed.
$applyAsync is also cool since you can batch up a bunch of callbacks to fire within then next digest.
I am working on a project where we were asked to "patch" (they don't want a lot of time spent on development as they soon will replace the system) a system implemented under ExtJS 4.1.0.
That system is used under a very slow and non-stable network connection. So sometimes the stores don't get the expected data.
First two things that come to my mind as patches are:
1. Every time a store is loaded for the first time, wait 5 seconds and try again. Most times, a page refresh fix the problem of stores not loading.
Somehow, check detect that no data was received after loading a store and, try to get it again.
This patches should be executed only once to avoid infinite loops or unnecessary recursivity, given that it's ok that some times, it's ok that stores don't get any data back.
I don't like this kind of solutions but it was requested by the client.
This link should help with your question.
One of the posters suggests adding the below in an overrides.js file which is loaded in between the ExtJs source code and your applications code.
Ext.util.Observable.observe(Ext.data.Connection);
Ext.data.Connection.on('requestexception', function(dataconn, response, options){
if (response.responseText != null) {
window.document.body.innerHTML = response.responseText;
}
});
Using this example, on any error instead of echoing the error in the example you could log the error details for debugging later and try to load again. I would suggest adding some additional logic into this so that it will only retry a certain number of times otherwise it could run indefinitely while the browser window is open and more than likely crash the browser and put additional load on your server.
Obviously the root cause of the issue is not the code itself, rather your slow connection. I'd try to address this issue rather than any other.
So yes, apparently it is possible to have long grid with lots of rows built with angular. But then a problem comes with data updates.
You see if I just get all (let's say 10 000 rows) and render them in my grid - that works. It just takes a few seconds initially. And
a) I don't have all the date up front
b) I need the grid to be responsive immediately.
I can just do that with throwing let's say only 100 rows at the beginning, and then slowly update data as it becomes available. And that turns out to be the problem. Everytime you push new rows into $scope.data - it blocks UI. So I need to be smart about these updates.
Maybe I should set an interval and update the data only every few seconds? That seems to be not working
Maybe I should somehow watch for mouse movements and once it stops moving - start/resume adding rows, once mouse-movement detected seize adding rows and wait for another chance? - What if user never stops moving the mouse? (say some sort of a psycho)
Experimenting with _.throtle and _.debounce didn't get me anywhere.
You guys have any ideas?
UPD: here's a crazy one: what if? instead of waiting till angular updates the DOM, create entire DOM structure in memory, right before the digest cycle (with no data) and then insert that HTML chunk (that would be faster, right?) And after that let angular do its magic, data should appear. Would that work?
You are going to run into performance issues when something changes even if you can get all those rows rendered to the DOM. And your user probably isn't going to scroll through 10000 rows anyway. I would just use pagination. e.g.:
<div ng-repeat="item in items | startFrom:currentPage*itemsPerPage | limitTo:itemsPerPage"></div>
If you really want to have everything on one page you could load the rows as the user scrolls. If you are interested in that solution checkout http://binarymuse.github.io/ngInfiniteScroll/
One of the things I've noticed that I stupidly used to ignore - the container has to have fixed height. That significantly makes updates faster. Although technically it doesn't solve the problem entirely
Consider the following Plunker:
http://plnkr.co/edit/10Rs92cRulf9VtI3Bav6
It appears to work correctly, but if you look at the console, you can see that something is wrong. With just that little table, Angular has already hit the Digest loop limit of 10!
it isn't a problem in a small dataset like this one, but the actual production page has 10 different filters and can span 30+ days. As the data grows, the $digest looping is getting way, way out of hand.
What can I do to stop it? I have been pouring over the source code trying to figure out why the Table keeps getting digested over and over and over again, even though the data isn't changing at all. Am I missing something?
Filters are really for massaging data for the view.
The filter on your ng-repeat that loops and creates the date range is causing the issue. ng-repeat is calling that filter every. time. it. 'repeats' :) and from what I can gather you only need to create the range once at start-up (or when data changes). If you move the date range creation code out of a filter it should be more performant. You might even consider moving the range creation server side.
Forked your plunkr http://plnkr.co/edit/XTn7hjbQgV1DxcBlOYVJ.