Let's say a web page has the following code loaded from an external JavaScript file:
(function(foo) {
function bar() {
// Do something
}
function baz() {
// Do something else
}
})(window, window.jQuery);
For arguments sake, let's say I'm writing a chrome extension that will load a script I created with changes to some of the existing code; perhaps changes to the bar function but not baz. I could copy all of the existing code, make my changes, and load the modified JavaScript after blocking the original, but I don't want to do that if I can avoid it.
Is there a way to modify the behaviour of existing nested functions without loading a whole copy of the modified code?
Not really, no.
This pattern, an immediately-invoked anonymous closure:
(function() {
// stuff
})();
is specifically used to hide the internal contents from the global namespace. Once that code finishes executing, there are no references that can access its internal contents.
So your plan of blocking the script and then providing your full copy seems to be the only one you can do.
Related
I have a website that has a lot of popups, whenever a user load a popup (via ajax) there is a JavaScript code also loaded in the popup, I want this JavaScript code to be removed when its popup removed.
Main site code:
<body>
...
<div id="popup" style="display:none">
</div>
...
</body>
and then a loader in js file:
$.ajax('url',{
success:function(data){
$("#popup").show().html(data);
};
});
one of the views that ajax call and push it in the popup:
some html codes
<script>
$(document).on('click',function(){
console.log("document click");
});
</script>
when the user closes the popup, I use this code to empty the popup:
$("#popup").hide().html("");
but this doesn't end the on click event that was loaded, and any functions in the view will still exist in the memory and can be called!
this is an issue because I have a lot of popups here, and JavaScript eats the memory after a while, so I need to refresh the browser after using the website for some time, plus, events are duplicated whenever the popup reloaded!
If it not possible to clear these JS from the memory, are there any workaround for it?
What I get from your question (if I understood it correctly) is you need a way to clean up your memory from unused functions (maybe variables too) with some events listeners, Here is my approach:
#1 - Use removeEventListener
removeEventListener is a method used to remove unwanted events listeners from event target for example:
// add click event to the body
document.body.addEventListener('click', function clickHandler(){
console.log("document click");
});
// remove click event from the body
document.body.removeEventListener("click", clickHandler)
#2 - Garbage Collection
JavaScript does not provide a direct way to clean up the memory from unnecessary data (function declaration or variables declaration) but we can trick it using Garbage Collection. Garbage Collection uses an algorithm for cleaning up the memory from unnecessary data called Mark and Sweep. Basically this algorithm clean up the memory through marking of all the nodes (Objects) that are not reachable though the root node (which is the global object in JavaScript) and remove them from the memory. We can use this to our advantage by using two things (IIEF and Block-Scoping).
IIFE
IIFE is an acronym for Immediately Invoked Function Expression. If you go more deep about IIFE you will find that the function created inside (...) are hiding in a different scope other than the global scope, which means that by creating a function as an IIFE we will prevent the global Object from accessing it which means it will get removed from memory by the Garbage Collector after it gets executed.
Take a look at this example:
(function foo() {
// your code goes here
})()
console.log(foo) // ReferenceError: foo is not defined
Block-Scoping
Introduction to Scope
A block statement is used to group zero or more statements. The block is delimited by a pair of braces {...} and may optionally be labelled.
If you declared your variables inside it using the let or const keywords, Your variables will be not reachable by the global object and then can be removed from memory by the Garbage Collector after it gets executed.
Take a look at this example:
function foo(data) {
// do something with the data
}
{
let someBigData = []
foo(someBigData)
}
console.log(someBigData) // ReferenceError: someBigData is not defined
Is it possible to find a randomly generated value declared within an anonymous function (IIFE), and if so how?
(function () {
// assuming an epic, obscured, random function
var salt = random()*10000|0;
// assuming an event manager
Events.on('custom event', function () {
// do something amazing with salt here
});
})()
Assuming:
the function is loaded via ajax
it executes on load (making it difficult to include a breakpoint)
there's a suitably elegant solution in place to test for injection (is there such a thing?).
A simple breakpoint in your JS exposes the salt value. It is not accessible to code outside the IIFE (Immediately Invoked Function Expression - what you are calling anonymous function), but if you're trying to keep a debugger from seeing it via a breakpoint inside the IIFE, then JS is not going to prevent that in any way.
For example, you can set a breakpoint right where the salt value is coined and see what it is or if that code is dynamically loaded via ajax, you can set a breakpoint on the ajax loading code and then step through the loading of the code until you can then set a breakpoint where the sale value is coined.
I see to ways to hack this, first set a breakpoint and overwrite the the salt, or overwrite Math.random to always return the same value. And there are no ways to protect your program from this. On the other hand its very hard to find the piece of code in a minified and obfuscated script.
In the rails.js that came with my rails (3.0.x, still with prototype), I see the following structure:
(function() {
// ...
document.on("click", ...
})();
What exactly is accomplished with the wrapping of the whole code in the anonymous function? Is this a valid way to delay the code until the dom has loaded or only the document object?
In my project, I currently have a lot of setup code inside a Event.observe(document, 'dom:loaded', function() { ... } block. I was wondering, if I should adopt the pattern above when I refactor my code.
You have stumbled across the module pattern. It is useful because variables inside the immediately invoked function are local and don't pollute the global namespace.
(function(){
var something = 17;
//can use something inside here
}());
//but not here anymore
Not ethat there is no difference in timeing since the function is immediately invoked (in the final () bit)
The self-invoking anonymous function will trigger what is inside immediately, which has nothing to do with delaying the code.
To make the code block inside be executed after the DOM is ready, you have to have DOMready listener. I guess the code you mentioned Event.observe(document, 'dom:loaded', function() { ... } is the one.
I'm debugging an app that uses .NET's scriptmanager.
It may be a glitch in firebug, but when I read through the code there are a lot of lines like the following:
// anonymous functions not attached as handlers and not called immediately
function () {
//code
}
// named functions added as methods
myObj = {
myMethod: function myFunctionName() {
//code
}
}
Are these lines valid and, if so, what do they do and what possible reason would there be for coding like this (and I won't accept "It's microsoft - what d'you expect" as an answer)?
This might be worth a read: How does an anonymous function in JavaScript work?
They are there because some busy programmer was intending to do something and ran out of time, but left the stub as a reminder of work to be done. They do nothing as of yet.
or to watermark the code for checks that are done elsewhere in the logic
or simply put there to obfuscate...
I am writing a web application that has a static outer "shell" and a dynamic content section. The dynamic content section has many updates as users navigate the system. When a new content block is loaded, it may also optionally load another JavaScript file. In the name of good housekeeping, I remove script blocks from the DOM that apply to old content blocks, since that JavaScript is no longer needed.
The problem comes next, when I realized that although I have removed the <script> element from the DOM, the JavaScript that was previously evaluated is still available for execution. That makes sense of course, but I'm worried that it may cause a memory leak if the users navigate to a lot of different sections.
The question then, is should I be worried about this situation? If so, is there a way to force the browser to cleanup stale JavaScript?
<theory>You could go with a more object-oriented approach, and build the model in a way that each block of javascript blocks come in as their own objects, with their own methods. Upon unloading it, you simply set that object to null.</theory>
(This is fairly off-the-cuff.)
Memory use is indeed an issue you need to be concerned with in the current browser state of the art, although unless we're talking about quite a lot of code, I don't know that code size is the issue (it's usually DOM size, and leftover event handlers).
You could use a pattern for your loadable modules that would make it much easier to unload them en mass -- or at least, to let the browser know it can unload them.
Consider:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function MyModule() {
function foo() {
bar();
}
function bar() {
}
}
return MyModule;
})();
That defines a closure that contains the functions foo and bar, which can call each other in the normal way. Note that code outside functions runs immediately.
Provided you don't pass out any references to what's inside the closure to anything outside it, then window.MyModule will be the only reference to that closure and its execution context. To unload it:
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
That tells the JavaScript environment you're not using that property anymore, and makes anything it references available for garbage collection. When and whether that collection happens is obviously implementation-dependent.
Note that it will be important if you hook event handlers within the module to unhook them before unloading. You could do that by returning a reference to a destructor function instead of the main closure:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function foo() {
bar();
}
function bar() {
}
function destructor() {
// Unhook event handlers here
}
return destructor;
})();
Unhooking is then:
if (window.MyModule) {
try {
window.MyModule();
}
catch (e) {
}
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
}
If you save the evaluated code in namespaces, such as:
var MYAPP = {
myFunc: function(a) { ... }
}
"Freeing" the whole thing should be as simple as setting MYPP to some random value, ala
MYAPP = 1
This does depend on there being no other means of referencing the variable, which isn't trivial
How about loading the JS files into an iframe? Then (in theory, never tested it myself) you can remove the iframe from the DOM and remove the "memory" it's using.
I think... or I hope...
If you are worried about memory leaks then you will want to make certain that there is no event handlers in the code you want removed referring to the still existing dom tree.
It may be that you need to keep a list of all event handlers your code added, and before unloading, go through and remove the event handlers.
I have never done it that way, I always worry about when I remove nodes that there is still a reference.
Here is a good article on javascript memory leaks:
http://javascript.crockford.com/memory/leak.html
JavaScript interpreters have garbage collectors. In other words, if you don't reference anything, it won't be keeping them around.
One of the reasons why it is good to use JSON with a callback function (JSONP).
example, if you HTTP response for each JS is:
callback({status: '1', resp: [resp here..]});
And if callback() does not create a reference to the JSON object passed in as an argument, it will be garbage collected after the function completes.
If you really need to make a reference, then you probably need that data around for some reason - otherwise you would/should NOT have referenced it in the first place.
The methods mentioned to namespace objects just creates a reference that will be persisted until the reference count comes to 0. In other words, you have to track every reference and delete it later, which can be hard when you have closures and references from DOM lying around. Just one reference will keep the object in memory, and some simple operations may create references without you realizing it.
Nice discussion. Clears up a lot of things. I have another worry, though.
If I bind window.MyModule.bar() to an event, what happens if the event accidentally gets triggered after window.MyModule is deleted? For me, the whole point of namespacing and separating js into dynamically loaded modules is to avoid triggering event handlers cross-module by mistake.
For example, if I do (excuse my jQuery):
$('.some-class').click(window.MyModule.bar);
What happens if I delete window.MyModule, load another module, and click on an element which accidentally has a class called some-class?