EDIT
I 've created this blnkr instead to make things more cleaner and independent on third party library so I 've added some dumy X string to an array in a component ,
to reproduce the issue
1 - Go this blnkr :
https://plnkr.co/edit/jG3HPOHFoBpFNy39?open=Hello.js&deferRun=1&preview
2 - Click Tab Two button
3 - Click the Grow button few times
4 - Take a heap snapshot
5 - Click the Grow button few times again
6 - IMPORTANT Focus the input elment
7 - Unmount the component (by clicking Tab One again )
8 - Click (GC button) and take another heapsnapshot
9 - compare with the first one
finally you will see the repeated X string under concatenated string field in the comparison which means the component that own this string is never cleared !
screenshot
I 'm using ag grid to build highly scalable data grid and it consumes significant amout of memory so optimizing the memory leaks is somehing necessary on my end , I 've noticed that using the <input type="text" /> and focusing or typing on it then destroying the react component doesn't acually remove the input element and its owner component from the js heap which causes a memory leak !
I 've created this plunker : https://plnkr.co/edit/18AQcdXgNIV1m6fW?preview
Screenshot of reproducing the issue (focusing the input element and then unmounting the component by clicking the toggle button and i can see many detached elements in the memory , is there a workaround into this , i 've also noticed that this is common within react components using input elements never garbage collected
Related
Here is an example to reproduce: https://codesandbox.io/s/crazy-kirch-f7fso8?file=/src/App.js
To reproduce:
right click and inspect the elements.
In your inspector (assuming you have this capability), right click on the div with the wrapper id and break on subtree modifications.
Click toggle button
Click "resume script execution" arrow to jump through each subtree modification.
Notice how initially, neither imported component renders, then they pop back in on a subsequent render.
Walking through the example in a bit more detail:
I am conditionally rendering 3 types of thing depending on a single variable using the ternary operator.
String - this seems to update immediately
Element - this seems to update just after the string does
Imported component - both components disappear, then one comes back (after element and string).
Does anyone know what may be causing imported components to briefly disappear? This is causing a flash of content that I'd like to avoid.
That is because A and B are different components, so on each toggle, you need to unmount the rendered one and mount the other. This means removing the node from the DOM and then inserting the other one.
The other cases are treated as the same element with just a text content change. Not mounting/unmounting happening here.
About the flashing, i cannot reproduce on FF or Chrome. Only if i have the break-on-modifications enabled i see it.
I've got a complex component which does all its rendering in a render function. There are multiple parts to this, and different bits of the view get rendered - one of these things is a filter bar, showing the filters that have been applied.
What I'm noticing happening, is if I apply a filter which in turn presents this bar, it causes everything else to be fully re-rendered. This is causing a number of other issues and I need to try and stop it from happening.
I've never come across this issue when using normal templates as Vue seems to handle these very intelligently, but I have no idea how to tackle this. The only thing I can think of is setting a key on each thing I don't want re-rendered but not sure if this will a) solve the problem, and b) be possible for the content that is passed in through a slot
Has anyone else faced this issue, and if so how can it be solved?
I had a similar issue when using vuetify text inputs in a complex component which was causing the app to slow down drastically.
In my search I found this link which was specific to vuetify:
high performance impact when using a lot of v-text-field
then found out that this is actually a vue thing from this GitHub issue:
Component with slot re-renders even if the slot or component data has not changed
and there is plan to improve this in it is tracked here (vue 3 should resolve this issue):
Update slot content without re-rendering rest of component
so after reading through all these I found some workarounds that helped me a lot to boost the performance of my app, I hope these will help you as well:
divide that complex component into smaller ones specially when there is some bit of code that changes data that bounds to template causing re-rendering (put them in their own component)
I moved all data layer control to the vuex store, instead of using v-model every where and passing data as events and props, all the data is updating in the store through an action and read from the store through a getter. (from data I mean somethings that is being looped in the template in a v-for, API results, and so on... all of them is being set, updated and read through the store. my components still have the data object but only for the things related to the style and template control like a boolean to control a modal or an imported icon which is used in the template and alikes)
lastly I wrote a function called lazyCaller which its job is to update the values in the store with a delay (when immediate data update isn't necessary) to avoid rapid updates comping from something like a text input (with out this every key stroke trigger the value update action)
I am not sure whether this question is asked before or not. But I got a serious problem with my angular application and I haven't find proper solution for the same.
In my application, I have used Angular JS 1.0.8, smartTable component and jquery Qtip v2.2.1. I have 4 tabs which have shows tabular structure using smartTable component.
In smartTable, If we want to customize any cell data then we have to create directive to customize cell template.
As per my functionality, I have to show tooltip on over of cell data. I observed that jquery qtip data wasn't destroyed if we call destroy method. and If I call destroy method then after that it will give "Uncaught error: unable to call method show of null". I have try to disable the qtip for a while and I observed significant change in heap size increase rate. This is one issue.
Second issue: When I switch between tabs to show different tabular data. it increase heap size upto 12 to 15MB each time. So, how to reduce heap size increase rate?
To control heap size issue I have written destroy event in each controller and directive. in destroy event block I am assigning null values to string, make arrays blank
Is this the right approach?
What should be the way to write the proper controller and directive code?
Please provide your suggestions
Thanks,
Jay
I'm developing a single page application that uses a lot of widgets (mainly grids and tabs) from the jqWidgets library that are all loaded upon page load. It's getting quite large and I've started to notice after using (I emphasize using because it doesn't start to lag after simply being open for any amount of time, but specifically, after opening and closing a bunch of tabs on my page, each tab containing multiple grids loaded thru Ajax that have multiple event listeners tied to each) the site for a couple minutes the UI becomes quite slow and sometimes non-responsive, when the page is refreshed everything works smooth again for a few minutes then back to laggy. I'm still testing on localhost. My initial reaction was that the DOM has too many elements (each grid creates hundreds of divs! And I have a lot of them) so event listeners which are tied to IDs have to search through too many elements and become slow. If this is the case it won't be too hard to fix, is my assumption likely to be the culprit or do I have worse things to fear?
UPDATE: here are captures of the memory time line and heap snapshot. On the memory timeline there was no interaction with the site, the two large increases are page refreshes, the middle saw tooth section is just letting my site idle.
Without seeing any code examples it doesn't sound too bad.
If you have a LOT of jQuery selectors try and make those specific as possible. Especially if you're selecting a lot of items a lot of the time.
For example, if you have a bunch of class "abc", try and specify before that where to look - e.g. are they only found within table cells? are they only found within paragraph tags? The more specific you make your selector the better as if you specify the selector like this:
$('.class')
Then it will search the entire DOM for anything that matches .class, however, if you specify it as follows: $('p .class') then it will only search all paragraph tags for the class.
Other performance killers are wiring up events and then never removing them. If you have any code that removes elements that have event handlers attached to them then best practice is to remove the event handlers when the element is removed. Otherwise you will start piling up orphaned events.
If you are doing a large single page application look to a library like backbone (http://backbonejs.org/) or angular (http://angularjs.org/) to see if this can help you - they alleviate a lot of these issues that people who use plain jQuery will run in to.
Finally, this post (http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/) is seriously good at outlining out you can write fast, efficient javascript and how to avoid the common performance pitfalls.
Hope this helps.
It does sound like you have a memory leak somewhere. Are you using recursion that's not properly controlled or do you have loops that could be ended early, but you fail to break out of them when you find something you're looking for before the loop naturally ends. Are you using something like this:
document.getElementById(POS.CurrentTableName + '-Menus').getElementsByTagName('td');
where the nodelist returned is huge and you only end up using a tiny bit of it. Those calls are expensive.
It could be your choice of architecture also. Hundreds of divs per grid doesn't sound manageable logically by a human brain. Do you address each div specifically by id or are they just an artifact of the lib you're using and are cluttering up the DOM? Have you checked the DOM itself as you're using it to see if you're adding elements in the hinterland by mistake and cluttering up the DOM with junk you don't use causing the DOM to grow continuously as you use the app. Are you adding the event handlers to the elements numerous times instead of just once?
For comparison, I too have a single page app (Google-Chrome App - Multi currency Restaurant Point of Sale) with anywhere from 1,500 to 20,000 event handlers registered making calls to a sqlite back end on a node.js server. I used mostly pure JS and all but 50 lines of the HTML is written in JS. I tie all the event handlers directly to the lowest level element responsible for the event. Some elements have multiple handlers (click, change, keydown, blur, etc).
The app operates at eye blink speed and stays that fast no matter how long its up. The DOM is fairly large and I regularly destroy and recreate huge portions of it (a restaurant table is cleared and recreated for the next sitting) including adding up to 1,500 event handlers per table. Hitting the CLEAR button and it refreshing the screen with the new table is almost imperceptible, admittedly on a high end processor. My development environment is Fedora 19 Linux.
Without being able to see your code, its a little difficult to say exactly.
If the UI takes a little bit before it starts getting laggy, then it sounds likely that you have a memory leak somewhere in your JavaScript. This happens quickly when using a lot of closures as well as nested function and variable references without cleaning them up when your done with them.
Also, event binding to many elements can be a huge drain on browser resources. If possible, try to use event delegation to lower the amount of elements listening to events. For example:
$('table').on('click','td', myEventHandler);
Be careful to make sure that event bindings only occur once as to avoid actions being unintentionally fired many times.
Good luck!
I'm working on a web app in ASP.NET 2.0 that involves several GridView elements. When users click one of the rows in a grid, that row needs to show its selection by changing color. Each row has attributes set to identify its record type and unique ID:
<tr data-elementType='myType' data-myID='12' onclick='selectionFunction();'></tr>
I accomplish the selection through a javascript onclick handler on each row that calls a function that:
Removes the selected class from the previously selected row
Adds the selected class to the new selected row
Updates the value of a hidden field with the new selected unique ID so server-side code can know which element to perform an action on when a button is clicked (view, delete, etc).
One of these grids now has just over 700 records in it. In Firefox 3.6, the selection operation on this grid is horribly slow (about two seconds); in other browsers (even IE 7 and 8) it's not a problem. I put console.log statements at the start and end of the selection function, and in Firebug they show up very fast at the end of the delay, suggesting that it's not the selection function that is slowing things down. I used the profiler in Firebug and it says that "createCallback", which is defined in one of the "ScriptResource" script files generated by ASP.NET, is taking the huge majority of the time. What is createCallback and why does it seem to be so slow in Firefox 3.6? Is it a bug in FF, or is it a problem I can solve?
UPDATE: I am, of course, using jQuery to add/remove classes from the rows. I've been working with jQuery 1.5.2 and jQueryUI 1.8.11, but I updated to the latest (1.6.2 and 1.8.14 currently) to no avail. I tried putting a breakpoint in createCallback to see where it's getting called, and when it breaks there it's several frames down in the call stack from my call to removeClass. Here is what the stack looks like in Firebug:
createCallback() - in ScriptResource.axd?......
wherever possible trim: trim ? function(text=" ") - in jQuery
removeClass(value="selectedRow") - in jQuery
removeClass(classNames="selectedRow", speed=undefined, easing=undefined, callback=undefined) - in jQueryUI
selectionFunction() - in my .aspx page
onclick
I don't understand why jQuery is triggering an ASP.NET generated function like this.
UPDATE 2: some more investigation has provided some more detail. It seems that this "createCallback" function is getting called A LOT when I use addClass/removeClass, and it's happening in both Firefox 3.6 and Firefox 5. I found the same function in Chrome and put a breakpoint on it, and it's not getting called at all, so this seems to be a Firefox thing. I put a breakpoint on the function/line in question and selected a row, and the breakpoint got it 57 times. Only the first two involved me calling removeClass and addClass; the rest had createCallback several times in the callstack, and sometimes BeginRequestEventArgs too. I've noticed it getting called also when I mouseover other jQueryUI stuff on the page (tabs), when jQuery uses addClass and removeClass. But why is it getting called so many times when I do work on tr elements?
I'm changing the title and tags to reflect the real issue.
UPDATE 3: createCallback is getting called about the same number of times whenever I select a row in any of the grids, even if it only has 6 rows in it. But in that case it's not a performance problem, and the profiler shows it only taking about 30% of the execution time, while it's at least 80% when I profile selection on the larger table. So createCallback seems to perform worse when it's used in the context of more stuff visible on the page. But it still seems like jQuery shouldn't cause a call to createCallback, especially since I couldn't fine any references at all to it in Firebug's script search. And it appears to only get called in Firefox!
Note also that all of these grids are on the same page, but only one is visible at once, because I'm using jQueryUI tabs.
UPDATE 4: I managed to get something similar up on jsFiddle as requested. See here. In Firebug, find createCallback and set a breakpoint (just below my click handler in the script, where it begins with Function.__typeName = "Function"; Function.__class = true; Function.createCallback = function (b, a) and reload the page. I get a lot of calls to it.
I have very little knowledge of ASP however it sounds like your problem is purely client side.
Declaring on "onclick" event for each row is not the most sensible way to handle the rows being clicked. Especially when you get into the quantity of rows you're talking about (~700+).
A better way would be to add a click event handler to the table and figure out what is clicked when it happens. I have written an application where a similar size table is being handled and we're not seeing anything like the lag you're experiencing upon click. there may well be other factors causing your click events to slow down however I would still suggest something along the following lines is worth implementing in any case:
$(function(){
var rowSelectedClass = 'rowSelectedClass';
$('#myTableID').click(function(e){
if(e.target.nodeName === 'TD'){
var $tr = $(e.target).parent();
$('tr.' + rowSelectedClass).removeClass(rowSelectedClass);
$tr.addClass(rowSelectedClass);
// ....
// Do whatever else you want to do when the row is clicked
// ....
}
});
}
A good article to take a look at which advocates this method (and a few other handy jQuery tips) can be found here: http://www.artzstudio.com/2009/04/jquery-performance-rules/#leverage-event-delegation
Also worth noting that if your table has rows added dynamically after the page is loaded then consider using .live() instead of .click().
UPDATE # July 28th 2011 9AM
Having taken a look at the source more closely, I think the supposed calls to "createCallback" are a red herring. The line within your original jsFiddle source which contains the "createCallback" function is actually a really long string (~90,000 characters) of javascript. I think the fact that "createCallback" is the first function within that string is misleading Firebug's profiler. When you profile your original page's load, there are 2261 calls and as you said, there appear to be lots to "createCallback"
I've "beautified" (hate that phrase) this long JS string via http://jsbeautifier.org/ to make it readable and re-added it to a jsFiddle page. You can see it here: http://fiddle.jshell.net/KvpmE/1/show/. Now when you profile this page's load you'll see a similar number of calls (2267 - not sure what happened to the other 6!) but importantly not a single one to "createCallback".
I still can't offer any solution though because essentially I've been unable to re-create your original issue which was that there was a 2 second lag in Firefox 3.6 when clicking a row.
Is this still the problem you're having?
Could you try and see whether you can re-create the problem within the updated jsFiddle page?
Also try and add the de-minified JS to your page to see if it helps you track down the actual functions being called when the row is clicked and therefore where the lag is taking place.
Mr. Jefferson,
It really sounds to me like you're actually performing a postback without knowing it. Have you set a breakpoint on the server side yet to see if something is inadvertently firing your update panel? It really sounds like some kind of postback is happening that is requiring a reload of dependant scripts.
I say this because 1) the problem you're having makes absolutely no sense - you're 100% on the money with JQuery and the ASP.NET Client Framework not even knowing they're neighbors in this case, and 2) the BeginRequestEventArgs instantiation sounds like the PageRequestManager thinks it should be doing something in response to your triggers... You could also try breaking out Fiddler and just doing a quick sanity check to make sure some update panel of yours isn't firing. There should be no HTTP traffic during the ops you're describing.
Sorry if this is an absolutely useless post for you, but with all of the work you've gone through to troubleshoot the client side it can't hurt to set a server side breakpoint just to do a quick sanity check / occam's razor...
Good luck - happy coding.
B
Function.createCallback is used a lot internally by Ajax Toolkit and maybe its being called within your code unintentionally too http://msdn.microsoft.com/en-us/library/dd409287.aspx.
Since this is browser dependent, I would check code paths that are executed based on a specific browser.
Another clue to look for is if you're having any Ajaxtoolkit components for the grid or its individual rows as that would explain the increase in number of calls with the increase in rows.
There is also Type.createCallback function (http://msdn.microsoft.com/en-us/library/bb397568.aspx) so if you have any Type related code or methods, I would check those.