IE 11 Out Of StackSpace - javascript

I have a rather large web app mostly written and tested on chromium. While testing it on IE11 it works for a while but then throws Out of stack space, and Stack Overflow at line 0. It is offering literally no way of debugging the issue. Does Internet Explorer handle circular structures differently by any chance? or does it run a limited memory per webpage. My computers task manager shows that IE is using around 1% of my memory where I have 12GB installed.
I have many Objects in this app such as the following...Not an actual snippet just an example.
var Classemployee=function(e){
this.id=e[0];
this.orders=[];
this.prefrences={
somePref:true,
1:blah,
........
}
}
var classOrder= function(e){
this.id=e[0];
this.server=employees[e[1]];
this.status=0;
this.seats={
1: new classSeat(this, 1),
..........
};
}
var classSeat = function(parent, id){
this.id=id;
this.parent=parent;
this.children=[
new classOrderLine(this.id, this.parent, arrayOfLineItemInformation)
]
}
var classOrderLine(parent, order, e){
this.id=e[0];
this.parent=parent;
this.order=order;
}
var orders={}
currentOrder=new classOrder(e);
orders[e[0]]=currentOrder;
The only thing i can think of is IE isn't handling these circular references properly but can't find any information on this subject.

After reviewing code further I found the problem was with a piece of code that was monitoring changes throughout the softwares memory By creating a hash of all of serialized objects. The way this code was written didn't realize there was a circular reference and continued looping through and for example storing data of:
orderline.parent.orderline.parent.etc....

Related

Try Catch Errors many script components - JavaScript

I have a page that contains many script components (50+) and I am getting an error when using IE at some random instance (doesn't happen in Chrome or Firefox).
"Out of Memory at line: 1"
I've done some google search too and that reveals issues with IE handling things differently to Chrome and FF. I would like to catch this error and know exactly what the cause of that script error is.
What would be the best way to use a global try-catch block on that many script components? All these script components are on the same page. Looking forward to your suggestions.
You might want to try window.onerror as a starting point. It will need to be added before the <script> tags that load the components.
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror
If that fails, you might try reducing the components loaded by half until the error no longer occurs. Then, profile the page (you may have to reduce further due to the demand of profiling). Look for a memory leak as #Bergi suggested. If there is in fact a leak, it will likely occur in all browsers, so you can trouble-shoot in Chrome, as well.
If that still fails to yield anything interesting, the issue may be in one particular component that was not in the set of components you were loading. Ideally, anytime that component is included you see the issue. You could repeatedly bisect the loaded components until you isolate the culprit.
Finally, forgot to mention, your home-base for all of this should be the browser's developer tools, e.g. Chrome dev tools, or if it is unique to Edge, Edge debugger.
And FYI, Edge is the browser that crashes, but that does not mean the issue is not present in Chrome or FF.
One important thing that is missing in your question is if the error happens during the page loading or initialization or if it happens after some time while you browse the page.
If it's during loading or initialization, it's probably caused by the fact that your page contains too many components and uses much more memory than the browser is willing to accept (and IE is simply the first one to give up).
In such case there is no helping but reduce the page size. One possible way is to create only objects (components) that are currently visible (in viewport) and as soon as they get out of the viewport remove them from JS and DOM again (replacing the with empty DIVs sized to the size of the components).
In case the error happens while browsing the page, it may be caused by a memory leak. You may use Process Explorer to watch the memory used by your browser and check if the memory constantly increase - which would indicate the memory leak.
Memory leak in Internet Explorer may happen because it contains 2 separate garbage collectors (aka GC): one for DOM objects and other for JS properties. Other browsers (FF, Webkit, Chromium, etc.; not sure about the Edge) contains only one GC for both DOM and JS.
So when you create circular reference between DOM object and JS object, IE's GC cannot correctly release the memory and creates a memory leak.
var myGlobalObject;
function SetupLeak()
{
myGlobalObject = document.getElementById("LeakDiv");
document.getElementById("LeakDiv").expandoProperty = myGlobalObject;
//When reference is not required anymore, make sure to release it
myGlobalObject = null;
}
After this code it seems the LeakDiv reference was freed but LeakDiv still reference the myGlobalObject in its expandoProperty which in turn reference the LeakDiv. In other browsers their GC can recognize such situation and release both myGlobalObject and LeakDiv but IE's GCs cannot because they don't know if the referenced object is still in use or not (because it's the other GC's responsibility).
Even less visible is a circular reference created by a closure:
function SetupLeak()
{
// The leak happens all at once
AttachEvents( document.getElementById("LeakedDiv"));
}
function AttachEvents(element)
{
//attach event to the element
element.attachEvent("onclick", function {
element.style.display = 'none';
});
}
In this case the LeakedDiv's onclick property references the handler function whose closure element property reference the LeakedDiv.
To fix these situations you need to properly remove all references between DOM objects and JS variables:
function FreeLeak()
{
myGlobalObject = null;
document.getElementById("LeakDiv").expandoProperty = null;
}
And you may want to reduce (or remove completely) closures created on DOM elements:
function SetupLeak()
{
// There is no leak anymore
AttachEvents( "LeakedDiv" );
}
function AttachEvents(element)
{
//attach event to the element
document.getElementById(element).attachEvent("onclick", function {
document.getElementById(element).style.display = 'none';
});
}
In both cases using try-catch is not the option because the Out of memory may happen on random places in code and even if you find one line of code where it's happened the next time it may be elsewhere. The Process Explorer is the best chance to find the situations when the memory increase and and trying to guess what may be causing it.
For example: if the memory increase every time you open and close the menu (if you have one) then you should look how it's being opened and closed and look for the situations described above.
You could check your localStorage before and after any components called.
Something like:
function getLocalStorage() {
return JSON.stringify(localStorage).length;
}
function addScript(src, log) {
if(log){
console.log("Adding " + src + ", local storage size: " + getLocalStorage());
}
var s = document.createElement( 'script' );
s.setAttribute( 'src', src );
document.body.appendChild( s );
}
function callFunction(func, log){
if(log){
console.log("Calling " + func.name + ", local storage size: " + getLocalStorage());
}
func();
}
try {
addScript(src1, true);
addScript(src2, true);
callFunction(func1, true);
callFunction(func2, true);
}
catch(err) {
console.log(err.message);
}
I hope it helps you. Bye.

When I destroy an ExtJs grid object its kept in the initialconfig, causing a massive memory leak, how do I get rid of this initialconfig properly?

I'm creating a grid inside a panel, and when I destroy the grid a reference to it is kept inside the initial config for the panel, meaning it's not ever cleaned up properly. Is there a way to stop this initialconfig from even being created/a way to clear it so hat objects it holds references to will be correctly cleaned up?
You can null it in Base destructor. Unfortunately Base is not a real class so overriding it via Ext.define is not the proper way but we can work around that with a closure:
(function() {
var oldDestroy = Ext.Base.destroy;
Ext.Base.destroy = function() {
this.config = this.initialConfig = null;
oldDestroy.call(this);
};
})();
I would strongly advise you to upgrade to Ext JS 6 if memory leaks are a problem in your app. We plugged most of the component leaks in 6.0, and unfortunately this effort is largely not backportable without major compatibility issues.

In Appcelerator Titanium How can I disable javascript code optimization to make debugging easier?

I'm working with an iOS targeted app built using Titanium (with Alloy); I want to be able to turn off the Javascript code optimization within Titanium Studio, but cannot locate anything by Googling, nor searching SO. When Titanium compiles it produces optimized javascript files...which makes interactive debugging difficult because in many cases it combines several lines of clean, readable code into a single line... which makes stepping into the code with the debugger difficult.
For example:
this...
if(Array.isArray(detailItemArray)){
//term-item.detail-items
for(var z=0;z<detailItemArray.length;z++){
if(z===0){
//first item in detail-item array gets a title pre-pended to it
// title is optional
if(_.isString(termItemArray[y].title)){
htmlArray.push(html.termItem(termItemArray[y].title,html.processStyle(detailItemArray[z]['style'],detailItemArray[z]['detail'])));
} else{
htmlArray.push(html.processStyle(detailItemArray[z]['style'],detailItemArray[z]['detail']));
}
} else {
//process style if available, then add to the array buffer
htmlArray.push(html.processStyle(detailItemArray[z]['style'],detailItemArray[z]['detail']));
}
}
} else {
//when detailArray is not an array (sometimes it is -- see if statement above)
//the title is optional
if(_.isString(termItemArray[y].title)){
htmlArray.push(html.termItem(termItemArray[y].title,detailItemArray['detail']));
} else {
htmlArray.push(html.termItemNoTitle(html.processStyle(detailItemArray['style'],detailItemArray['detail'])));
}
}
turns into this...a single line...
if (Array.isArray(detailItemArray)) for (var z = 0; detailItemArray.length > z; z++) 0 === z ? _.isString(termItemArray[y].title) ? htmlArray.push(html.termItem(termItemArray[y].title, html.processStyle(detailItemArray[z]["style"], detailItemArray[z]["detail"]))) : htmlArray.push(html.processStyle(detailItemArray[z]["style"], detailItemArray[z]["detail"])) : htmlArray.push(html.processStyle(detailItemArray[z]["style"], detailItemArray[z]["detail"])); else _.isString(termItemArray[y].title) ? htmlArray.push(html.termItem(termItemArray[y].title, detailItemArray["detail"])) : htmlArray.push(html.termItemNoTitle(html.processStyle(detailItemArray["style"], detailItemArray["detail"])));
using Titanium Studio v3.2.3.201404181442
Any ideas if there is a setting that can temporarily disable this behavior so interactive debugging is easier?
Thanks in advance.
--Scott
EDIT: A suggestion from a co-worker was to sprinkle some log statements in the code (like right after the "for" statements; and sure enough this prevented the optimizer from in-lining the code. Not exactly how I wanted to go about it, but, at least got me moving forward. Would still like to find a way to turn down the JS optimizer level or off.
Try titanium build -p ios --skip-js-minify.
From titanium build --help:
Build Flags:
--legacy build using the old Python-based builder.py; deprecated
--skip-js-minify bypasses JavaScript minification; simulator builds are never minified; only
supported for Android and iOS [default: false]
-b, --build-only only perform the build; if true, does not install or run the app
-f, --force force a full rebuild

Weird Javascript IOS 7 Issue

I have a web application which behaves fine on all desktop browsers and mobile devices however since IOS 7 I am encountering a weird issue.
Example:
I am setting an object like
(function(){
//CONSTRUCTOR*
sampleObject= new function(){
alert("loaded constructor "+ new Date().getTime()); //only outputted once
//swfobject dom load event
}
...//functions and propeties related to sampleObject
})();
//ASSIGNING THE OBJECT
sampleObject = new sampleObject();
alert("finished assigning object "+ new Date().getTime()); //only outputted once
Issue:
On ios 7 it seems to randomly lose what sampleObject is and instead reverts to what is inside the snippet with constructor*. So for example, I have been debugging it at intervals where I am calling a public method on my object such as sampleObject.getResource("a");
And the traces are coming back like:
sampleObject = [Object] //Correct
sampleObject = [Object]
and then randomly it does this:
sampleObject = function(){
//swfobject dom load event
}
Which basically is the code inside the constructor*.
This then causes my code to throw a reference error as the public properties/methods which I am using throughout such as getResource are not defined...
Things Tried:
Code only initiates once (alerts fire once with single Date / random string)
I Identified where an error was occuring due to this issue, wrapped around a try/catch however although the code is clearly failing it is not going into the catch.
Tried it on different IOS versions, all fine except IOS 7
*CONSTRUCTOR - not sure if this is classified as a constructor but that is what it seems to me.
**Unfortunately I cannot post my code publicly as it is part of a commercial project and quite extensive.... However any suggestions or has anyone had any similar issues?
Thanks!
Thanks for all the comments above. That pointed me in the right direction.
The problem seems to be that IOS 7 seems to randomly loses scope of the javascript object, and because we werent specifically assigning the sampleObject to the window then it wasnt working all the time.
Therefore solution to my problem was simply to change:
//ASSIGNING THE OBJECT
sampleObject = new sampleObject();
to
//ASSIGNING THE OBJECT
window.sampleObject = new sampleObject();

Enable/Disable debug code dynamically

I'm writing a decent sized JavaScript animation library, that I would like to include debugging code in. I could easily do a check :
if(myLib.debugger){
console.warn('warning message');
}
However if this runs a couple thousand times a second, it would eventually cause performance issues. Add in a few more checks throughout the code and the effect will be even more noticeable.
What I'm wondering is if it would be possible to check onload if the debugger should be enabled, and if so... turn something like this:
//debugger if(!this.name) console.warn('No name provided');
into:
if(!this.name) console.warn('No name provided');
Leaving the code commented if its not enabled, and uncommenting it if it is, thus removing any possible performance issues. Could this be done somehow with a regular expression on the entire script if loaded in through ajax? I'm trying to avoid the need for 2 versions of the same code, lib.dbug.js and a lib.js.
Cross browser compatibility is not of great importance for this (I'm really only worried about new browsers), I see it as nice to have item. If its possible however, it would be a great thing to have.
Any insight would be greatly appreciated.
The simplest way to do this would be to check if the debugger should be disabled and if so, replace it with a mock object that does nothing at the very start of your script:
if (!myLib.debugger) {
window.console = (function () {
var newConsole = {};
var key;
for (key in window.console) {
if (typeof window.console[key] === 'function') {
newConsole[key] = function () {};
}
}
return newConsole;
}());
}
The overhead of this approach should be negligible.
If this is a JavaScript library... then I'd expect as a 3rd party developer that I could download/use 2 versions. The production version (no debug, AND minimized). If I wanted to debug, I would point to the debug version of the library instead.
e.g.
<script src="foo-lib-min.js"></script>
<!-- swap to this for debugging <script src="foo-lib-full.js"></script>-->

Categories

Resources