I have an app with a top frame and two framesets inside this top frame. While navigating to other pages the top frame remains the same and only the framesets change. I use localStorage for storing some data (which is also stored on the server, but if it is on client we don’t make the round trip each time), this feature is not available on IE7 so we decided to try to simulate localStorage in IE7.
The idea was to store a variable localStorage on the top frame (only if localStorage was not available). Whenever localStorage was not available on the top frame we would then create a dummy localStorage object with _data,getItem(),setItem(),removeItem(). The life of this object would last as long as the life of the top frame, which would save us a lot of round trips to the server and therefore offer a great performance boost in IE7.
The problem that I’m having is that whenever I change the frame (not the top frame) and I get the localStorage from the top frame and try to get an item using the window.top.localStorage.getItem(‘…’); I get the error message can't execute code from a freed script.
Any ideas why I get this??
I would recommend you to take a look in jStorage which provide common interface for localStorage, or old globalStorage or userData behavior. Probably you can use jStorage directly (see here) and save your time writing the corresponding code or you can use the same idea for your own implementation. More information about old userData behavior you can find for example here.
Maybe I will be repeating what Brilliand already shared, but as I don't understand his answer entirely I will share some ideas/advice as well:
First of all make sure that all relevant frames are hosted on the same domain (including things like opening the top frameset on www.domain.com and having internal links without the "www.")
In case you need cross domain scripting check out the internet for some relevant tricks to achieve that (the theory).
It might be worth trying to wrap all access to the localStorage within a few functions in the top frame (I can think of a few reasons which could theoretically cause problems with direct access to objects in the top frame... although this should as far as I know work).
Try reinitialize all references to subframes, you might for example have forgotten adding a "var" in front of a window.frames reference and not reinitalizing it after navigation (it would explain the error message, although it seems quite an unlikely mistake).
It might be also worth making sure to not keep any references to top.localStorage itself inside any of the child frames (although, again, it shouldn't cause any problems).
You might want to consider using a cross platform localstorage wrapper. They tend to work with proprietary functions in IE allowing a localStorage like functionality in IE as well (1MB max, but that should be enough). An example of such a library is store.js
See What causes the error "Can't execute code from a freed script"
That error message occurs when code created by the child frame (which has since been closed) is accessed. This means, at least, that you can't keep JavaScript functions around after the window they came from was closed; I'm not certain that applies to data objects as well, but it might. If so, then simple storage of JavaScript objects in the top window won't work.
It should be possible to work around this problem by ensuring that you completely detach the data from the child window before storing it. This can be done by having the storage function (which must be created by the parent window alone) JSON encode that data, and store the encoded string. Retrieval would be less finicky, since the retrieved object doesn't need to be kept around longer than the child window that retrieved it.
Related
Which tool is used to discover what JS/jQuery is consuming too many resources or in infinite loop?
More specifically I have an issue with this template: http://pages.revox.io/dashboard/latest/html/
Opening that page on Firefox 46.0.1 freezes the page after a few minutes. I'm unable to discover which JS/jQuery is causing this freeze with Firebug since it seems to be a script that is simply consuming too many resources and not in a plain freezing never ending loop (which would trigger the "Script XYZ is taking too long to execute" message)
Firefox 46.0 for Ubuntu appears to have a pretty good debugger built into it.
Using the system monitor it's easy to see your page requires a fair amount of memory.
It's fairly easy to produce a call graph in Firefox if you go to Tools->Web Developer->Performance and record your page for a little while.
Once you've stopped the recording, just select the data in the menu on the left and Call-Tree on the top of the debug frame.
It presents a breakdown of which functions use the most processor time.
Looks to me like whatever the Gecko function is, it is just really expensive.
Also, the console points out some interesting things:
mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create d3.v3.js:3:157
Use of getPreventDefault() is deprecated. Use defaultPrevented instead. html
Empty string passed to getElementById().
Maybe addressing the issues pointed out by the console will help your freezing issue.
This question already has answers here:
why does variable 'name' doesnt need to be initialized after first use [Javascript] [duplicate]
(3 answers)
Closed 7 years ago.
I was doing some experimenting on an HTML page, and say if I do
name = "hmm";
console.log(name);
and I load it inside of Google Chrome, and displayed "hmm" naturally.
The thing is, if I remove the first line or comment it out, and reload the page, it will show "hmm" again. If I create another webpage index2.html and also ONLY do the
console.log(name);
and change the URL in my browser from index.html to index2.html, it will show "hmm" again.
So I think it is due to window.name having this value. But, I never knew two pages can share values like that. I thought the window object should start fresh and should not carry any value over...
It only happens with name. It doesn't happen with foo, but still, I think even name should not carry over.
What is happening? And what about cross website (cross domain?) That really shouldn't happen, even if it is same website, should it?
I never knew two pages can share values like that.
Yeah. Normally, they don't. This is only happening because you used the specific variable name name, and used it in the global scope where it means the same thing as the window property of the same name.
window.name is an oddity dating from the early days of cross-document scripting. As a design it doesn't make any sense today but it's very difficult to get rid of old web behaviours.
When Netscape introduced JavaScript and frames in Navigator 2.0, security wasn't the first priority. The web was a different, less-threatening place, and for business reasons they were more concerned with adding any and all possible features into the browser than designing a coherent and secure platform.
The Same Origin Policy was in its infancy and wasn't regarded as an essential fundamental safeguard, more an undesirable encumberance pending the design something better and more permissive. They had a blacklisting instinct: add features and allow access by default, unless it's proven to be a security problem.
The window.name property on pop-up windows reflects the name argument of the window.open method that was called to open it; on frames, it reflects the name attribute of the <frame> (or <iframe>) element that included it. It was expected that scripts would want to access and navigate related windows (and even sub-windows, eg a frame inside a frame) by name even across different domains and even when the original document had been navigated.(*)
Consequently a number of properties of window, including name, were made accessible from outside the origin, and for compatibility remain there today, with a whole load of complex caveats and limitations that have arisen from the endless stream of browser security holes that resulted.
(* It turns out not many people wanted to do that, but they did want to be able to pass string data between two windows on different domains. These days we would just use window.postMessage which is designed for this explicit purpose, but back then the only way to do it was to use the only property that was read-write to both parties, name. This was clumsy and limited but a number of existing web sites did it, making it very difficult to remove from the web platform.)
Upshot: putting stuff in window can have unforeseen consequences, so try to keep global variables to an absolute minimum, and avoid existing properties like name.
say I have the javascript:
/*getAttribute is mootools method for retrieving a named attribute*/
var companyNumber = button.getAttribute('data-company-number');
var payPoint = button.getAttribute('data-pay-point');
window.location = '/Payslip/ListPayslips/?companyNumber=' + companyNumber + '&payPoint=' + payPoint
delete payPoint;//is this necessary?
delete companyNumber;//is this necessary?
Would the delete lines be necessary? And would they even get called?
No its not necessary, after the redirect all variables and instances will be deleted.
To answer the first question, yes. Everything is garbage on unload (unload fired on refresh, redirect or close).
To answer the second question, the deletes will not be hit after the redirect. The JS engine will stop there and fire unload etc.
As for the discussion around memory management and explicit variable deletion, here are some considerations:
Good memory management can become important when developing larger web apps that are left open in browser for long periods of time, especially when the target client browsers can be older or on slower machines or mobile devices.
In these cases, where you declare variables to hold temporary information, particularly large objects, you may choose to delete these to free them up for garbage collection. It is my opinion that you should avoid new declarations if they are not necessary and re-use objects where you can - but perhaps not at the expense of readability ;)
To add to 'Corey Ogburn's point, delete itself does not free memory, but disconnects a variable from it's value. It is this that frees the variable for garbage collection.
Yes, you lose all the variables if the redirect loads in the current frame/document. The best way to handle this is to create a couple of divs and any redirects need to be loaded in the other div. For instance, you could have a header and main div. Your JS can now reside in the page and any redirects should be loaded into the main div. That way you are preserving state.
An alternative is to use the HTML5 local/session storage.
EDIT:
Your second question which is at the bottom regarding delete. No, delete is not necessary. Others have responded with links and reasons why.
While reading about navigator() object in JavaScript I run into taintEnabled() function description, as good as similar taint() and untaint() functions, referring to something called "data-tainting".
Googling around net and StackOverflow show some possible reference to Perl language, but none about JavaScript. I wonder, what is data-taining and how to use these functions?
Data Tainting (or Taint Checking) is a language feature wherein user-input data is flagged as tainted, a flag that propagates to all data derived from this input. As a result, code can implement runtime assertions to ensure security critical code is not being called using tainted data (ie prevent SQLi, XSS type attacks).
Whilst Netscape implemented it in the browser in v3 and v4, support for it sadly never materialized elsewhere, so #trejder is absolutely right that it should be avoided in JavaScript.
As mentioned, there aren't many sources in the Internet about data-tainting, as it seems to be a long forgotten, deprecated technique and topic. But I found out an interesting reading on this on findmeat.org. For the Navigator.taintEnabled() method it says that (various parts cited, some text shortened):
The data-tainting support was a short-lived means of sending data back to a server. The security implications became unworkable and the whole data tainting idea was deprecated. The functionality was removed in JavaScript version 1.2. This method is only supported in order to prevent scripts from crashing. This functionality is highly deprecated and you can expect it to cause run-time exceptions in future. You should seek to try and remove it to prevent run-time errors in the future.
It seems that nowadays few browsers support this function (and similar, mentioned) and that it should not be used under any circumstance. Even if a browser implements this at all, it should return the value false for this method, always.
Lack of information on this concept makes new learners to make more effort. Here is my finding to help them.
When tainting should be enabled and when not, here are the two important points worth considering:
When data tainting is enabled, JavaScript in one window can see properties of another window, no matter what server the other window's document was loaded from. However, the author of the other window taints (marks) property values or other data that should be secure or private, and JavaScript cannot pass these tainted values on to any server without the user's permission.
When data tainting is disabled, a script cannot access any properties of a window on another server.
A useful resource is http://www.aisystech.com/resources/advtopic.htm#1009533
imagine that we have loaded a complex website with lots of Javascript which loaded all sort of info via AJAX and by making computations based on user input. So, now suppose we want to archive it in such a way that we can reliably load it later on from file (maybe even without an internet connection) and study its behavior / debug it / etc. Is there a way to do this?
The browsers already do this to make the "Back" button work fast -- in Firefox it's called "bfcache". This cache lives only in memory, though. I don't know if it's possible to serialize it to a file, if yes, it would be very interesting.
I don't think there's a way to export the entire DOM state without manually looking at each piece, and storing it. There is a lot of information that goes in representing that DOM than what visible in the source.
For instance, you might want to save the window scrollbar position which is available in the window object as window.scrollX and window.scrollY. This is just one example but there's plenty of other state information to be saved including attached event handlers etc.
If you could identify the pieces that are relevant for you purposes while ignoring others, you could store it locally using Google Gears (now obsolete) or the new Local Storage introduced in HTML5 and if you are already serializing this information, you could pass it on to some server and restore it from there. The new storage mechanism in HTML5 is called DOM Storage but its a little misleading because it's just a key value pair storage where both the keys and values are strings.
Edit: This might be a different perspective on the problem but here it goes. Instead of storing the entire DOM state, you could store just the intial state, and the relevant actions that change it. To get to the final state, a replay mechanism would be used that runs each action in sequence. This is a popular design pattern known as the Command pattern. That's how multiplayer games keep each player up-to-date and in-sync by passing only the player actions like a keystroke, mouse movement, etc. instead of the entire view and the receiver applies those actions to update its state. It's a lot more complicated than that in practice but thats the crux of it.
Where would you want to store it?
Currently there's no way to store anything browser side (apart from new browser features, that very few people have installed). The only realistic solution would be in a Cookie if the DOM is small enough (this is because a Cookie can only hold a certain amount of data).
If you're looking at storing the DOM server-side, then you could use document.body.innerHTML to access the current DOM state and then send it to your server.