If i have a function like this
function do(callback) {
//do stuff
callback();
}
and then I pass in an anonymous function:
do(function() { //do something else });
does that anonymous function ever get collected during the lifespan of the page? If not, how can i make it available for GC?
do I have to do this?
var h = function() { //do something };
do(h);
delete h;
Do I even have to worry about this? I am building a web app that has a long lifespan, makes a lot of ajax calls keeps objects for a while and doesn't really require a page refresh to navigate thru. So I'm trying to figure out if I might fall into a memory leak monster.
The only reference to the anonymous function is the function argument, and that disappears when the function finishes, so your callback will be available for garbage collection after that. Except when something else gets a reference to it, which can happen easily with closures:
function doo(callback) {
$.get(url, function() {
// callback is visible here!
});
callback();
}
doo(function() { /* do something else */ });
callback (along with the whole scope created by calling doo) must stay in the memory, because the inner function can reference it through the closure; it can only be garbage collected when the inner function is garbage collected, and since that function is a property of the jqXHR object, that object must be garbage collected before that, and who knows when that will happen...
Update You can avoid unnecessary closures by not defining your functions inside other functions:
var func = function() {
// callback is not visible here
}
function doo(callback) {
$.get(url, func);
callback();
}
doo(function() { /* do something else */ });
Watch out for circular references, otherwise the GC for the browser will clean those up. Closures make it really easy to create a circular reference, and that might be trapped in memory even if you browse away from the page that created it. So, web applications that stay on-screen for long periods of time are especially vulnerable.
Check out the section "Memory leaks" here: https://developer.mozilla.org/en/A_re-introduction_to_JavaScript.
I've designed quite a few static-page web applications. I've found that even when you don't have to clean up objects and event handlers (ie you're sure there is no circular reference), it can't hurt. It usually only adds a couple of extra lines of code, and it keeps memory use and efficiency at the forefront of your mind as you write your code. This is something of a shift for web developers because we usually don't have to think about this kind of thing very much when creating a website.
Related
Coming from a C++ background, trying to work with an OO language that doesn't have explicit typing is a little more than a headache.
So I have dynamic elements for a webpage that are "controlled" by objects since there are tons of stuff I need to manage on each for it to work. The element is just the visual output of the data inside of the object itself, that's all I really need it for.
Except that I need the object to perform an internal function when it's clicked. That seems to be the biggest source of my headache thus far.
Javascript:
function onClick(file) //The external onClick function I use to try to get it to call from.
{
file.state = INUSE;
file.checkState();
}
function fileObject () { //The file object itself
this.element;
this.newElement();
//initialize stuff for the object
}
fileObject.prototype.newElement = function() { //creates a new element and sets its event listener
this.element.click(function() {onClick(this)});
}
fileObject.prototype.checkState = function() {/*does stuff*/} //apparently this is "not a function"
The error I get exactly is "file.checkState is not a function" from Firefox's console panel.
I'm still new to javascript, but after doing some debugging, I've come to find out that it's explicitly the onClick(this) function that is causing all of the errors. When used with something else, the onClick function works perfectly, but for some reason, the this keyword doesn't appear to actually be sending the reference to the fileObject since all checks show file being undefined when inside of the onClick scope.
Is there something fundamentally wrong about the way I'm trying to do this or am I just missing a step (or adding something that I don't need) that will help get this snippet working.
So you know, your initial problem isn't actually handling the action, but listening to it. click will trigger a synthetic click event, rather than liste for one.
You want ... .element.addEventListener("click", callback); that said, you face a second problem, immediately thereafter.
I will leave my example code as you've written it to not confuse the matter...
But when you see click( ) know that I mean subscribing with addEventListener, if element really does mean a browser DOM element. If it's not a standard browser element, and your own API, then ignore the previous portion, and carry on.
this is dynamically bound at the invocation time of the function (not at definition time).
The nearest function, scoped above, is your callback function that you are passing into .click( ... ).
Which is entirely different than the this which you mean outside of the callback.
Whatever is on the left-hand side of the dot is the this context for the duration of that particular invocation.
Needless to say, click() doesn't know enough to bind the this you mean, to the left-hand side of your callback.
The solution (or one of many) is to use lexical scoping and/or closure to retain the value of the object you mean.
// easy but messier
var fileObject = this;
... .click(function () { onClick(fileObject); });
// Cleaner with thunks:
function clickHandler (onClick, obj) {
return function () { onClick(obj); };
}
... .click(clickHandler(this));
Coming from c++ the way Javascript handles this will seem a little crazy, it looks like here you need to tell the function you've defined what this is - like so:
this.element.click(function() {onClick(this)}.bind(this));
Let's say I'm creating a chat system in javascript.
var ChatController = function() {
this.receiveMessageInteractor = new ReceiveMessageInteractor(this);
// ReceiveMessageInteractor delegate
this.didReceiveMessage = function(message) {
// ...
};
};
The ChatController also does some other stuff related to creating the html for the messages, but that's not important here.
The ChatController sets himself as a delegate of the ReceiveMessageInteractor, which will call the didReceiveMessage when a new message arrives.
var ReceiveMessageInteractor = function(delegate) {
this.observer = NotificationCenter.addObserver('DidReceiveMessageNotification' , function(data) {
var message = data['message'];
// format some message data
delegate.didReceiveMessage(message)
});
};
The ReceiveMessageInteractor just subscribes to a notification (NotificationCenter here is similar to the iOS one), does some formatting with the data and passes a message object to the delegate;
When the chat view goes of the screen (html gets deleted), my MenuController stops holding a pointer to ChatController, in which case I'd like it to be deleted, along with ReceiveMessageInteractor and observer.
The problem is that Javascript has no weak references, so ReceiveMessageInteractor is holding a pointer to ChatController, and even if ChatController wasn't holding a pointer to ReceiveMessageInteractor, my ChatController would still be alive, because the notification callback is holding a pointer to it (delegate).
So even if ReceiveMessageInteractor stopped existing, my ChatController would still not go away when the MenuController stops holding a pointer to it (because I can't have a weak reference inside the notification callback).
How do I solve this problem?
How do I solve this problem?
By understanding JavaScript. The problem is not that "Javascript has no weak references", the problem is that you don't know how to work without them because you come from a language that has them.
How would you remove that reference in any other language that doesn't have weak refs natively? Let's say C++. You would do like everyone does, including the implementors of the compiler/garbage collector/weak refs you're used to: you clean up after yourself.
function ChatController() {
this.receiveMessageInteractor = new ReceiveMessageInteractor(this);
// ReceiveMessageInteractor delegate
this.didReceiveMessage = function didReceiveMessage(message) {
// ...
};
this.destroy = function destroy() {
this.receiveMessageInteractor.destroy();
};
};
function ReceiveMessageInteractor(delegate) {
function callback(data) {
var message = data.message;
// format some message data
delegate.didReceiveMessage(message);
}
this.observer = NotificationCenter.addObserver('DidReceiveMessageNotification', callback);
this.destroy = function destroy() {
// Or however you NotificationCenter works, I don't know
NotificationCenter.removeObserver('DidReceiveMessageNotification', callback);
};
};
The Observer pattern implies resource management, even though it's not obvious (how is an "observation" relationship a resource??). Acquire and release. No hand-holding.
Also, notice the change in style. And please, learn the language, use prototypes, and, although not everyone will agree with me on this point, do not assign methods in the constructor.
edit: I forgot to add: ReceiveMessageInteractor? Really? What's wrong with MessageReceiver or something in that vein?
Your problem is not with the absence of weak references. All of your objects continue to have a hard reference, all originating from your NotificationCenter.
The NotificationCenter has a reference to the data handler, which has closure access to it's parent ReceiveMessageInteractor instance, as well as access to the delegate variable. Removing a reference to delegate from elsewhere won't break the anonymous function's access to it, therefore it stays.
What you'll need to do is add a .cleanup() method to each Controller that is called when it is removed.
In the ChatController.cleanup() method, you would want to call a method to remove the observer, something along the lines of this.receiveMessageInteractor.observer.unsubscribe().
The .unsubscribe() method should be defined in the NotificationCenter and remove the function(data) { ... } method you defined in .addObserver() from whatever data structure is holding it (or further down the line).
This is the same kind of pattern Facebook utilized in it's React framework + Flux architecture. Each component has a componentWillUnmount() method that assists in cleaning up data event handlers just like yours.
I have tried searching through a lot of S.O. pages but nothing has touched EXACTLY on this top while also NOT USING JQUERY.... I am trying to stick to pure JavaScript as I want to learn it 115% before advancing my current knowledge of JQuery.
I have an object called ScreenResizeTool like this...
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg);
}, true);
}
and a method like this...
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
My trouble is probably obvious to an experienced JavaScript user but I am having trouble not making this into a messy dirty awful OOP set. I have done various tests to show and prove to myself that the this inside the addEventHandler changes when it becomes bound to the window. This much I assumed before testing but I was able to see that once window.resize event happens the listen method is gone and not a part of the global window variable....
I have also tried adding a this capture such as this.me = this inside the object constructor however it also couldn't see the me variable once it ran. Once the window took the function over it no longer knew anything about the me variable or any reference to my class methods....
I am aware that I could separate this differently but my goal here is to learn how to fully encapsulate and use as many clean OOP structures as possible as I just came from the .NET world and I need it in my life.
I am also aware that I could make messy calls and or store this object or access to the methods inside the window variable but that seems outright wrong to me. I should be able to fully encapsulate this object and have its events and methods all implemented in this class structure.
I also know that the currImg variable is not going to be seen either but lets start small here. I assume once I figure out my incorrect train of thought on scope for JavaScript I should be fine to figure out the currImg problem.
I know there's 1000 JavaScript programmers out there waiting to rip me a new one over asking this simple question but I gotta know...
Thoughts anyone?
this inside a function bound to a DOM Object (like window) will always refer to that object.
this inside a constructor function will always refer to the prototype.
A common practice to circumvent the this issue, as you mentioned, is to cache it in a variable, often called self. Now you want the variables and properties of your object available after instantiation, so what you need is the return keyword, more specifically to return the parent object itself. Let's put that together:
function ScreenResizeTool() {
var self = this;
// method to instantiate the code is often stored in init property
this.init = function() {
window.addEventListener('resize', function() {
self.listen(); // self will refer to the prototype, not the window!
}, true);
};
return this;
}
ScreenResizeTool.prototype.listen = function() { // Dummy function
var h = window.innerHeight, w = window.innerWidth;
console.log('Resized to ' + w + ' x ' + h + '!');
};
Pretty easy huh? So we have our prototype now, but prototypes can't do anything if there's not an instance. So we create an instance of ScreenResizeTool and instantiate it with its init method:
var tool = new ScreenResizeTool();
tool.init();
// every time you resize the window now, a result will be logged!
You could also simply store the listen & init methods as private functions inside your constructor, and return them in an anonymous object:
function ScreenResizeTool() {
var listen = function() { ... };
var init = function() { ... };
// in this.init you can now simply call listen() instead of this.listen()
return {
listen: listen,
init: init
}
}
Check out the fiddle and make sure to open your console. Note that in this case I'd rather use the first function than the second (it does exactly the same) because prototypes are only useful if you have multiple instances or subclasses
The whole concept of this in JavaScript is a nightmare for beginners and in my code I usually try to avoid it as it gets confusing fast and makes code unreadable (IMHO). Also, many people new to JavaScript but experienced in object-oriented programming languages try to get into the whole this and prototype stuff directly though the don't actually need to (google JS patterns like IIFE for example as alternatives).
So looking at your original code:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
listen(currImg); // global function listen?
}, true);
}
ScreenResizeTool.prototype.listen = function(currImg) {
//Random Code For Resizing
};
First off, you probably mean addEventListener instead. In its callback you refer to listen but as a global variable which would look for it as window.listen - which doesn't exit. So you could think to do this:
function ScreenResizeTool(currImg) {
window.addEventHandler('resize', function() {
this.listen(currImg); // what's this?
}, true);
}
As you want to use the prototype.listen function of ScreenResizeTool. But this won't work either as the event listener's callback function is called with a different this and not the this that is your function scope.
This is where something comes in which makes most programmers cringe, you have to cache this, examples from code I've seen:
var _this = this;
var that = this;
var _self = this;
Let's just use the latter to be able to refer to the function within the event callback:
function ScreenResizeTool(currImg) {
var _self = this;
window.addEventListener('resize', function() {
_self.listen();
}, true);
}
Now this will actually work and do what you want to achieve: invoke the prototype.listen function of ScreenResizeTool.
See this JSFiddle for a working example: http://jsfiddle.net/KNw6R/ (check the console for output)
As a last word, this problem did not have anything to do with using jQuery or not. It's a general problem of JS. And especially when having to deal with different browser implementations you should be using jQuery (or another such library) to make your own code clean and neat and not fiddle around with multiple if statements to find out what feature is supported in what way.
I pass an anonymous function-A as parameter to another function-B. Even after I call B.destroy, function A exists and gets executed, it even as an live anonymous scope to itself. I found this unexpected behavior through debugger. Following is the code.
var builder.record.verifyExplorer = new builder.VerifyExplorer(
window.bridge.getRecordingWindow(),
builder.getScript().seleniumVersion,
function(step) {
builder.getScript().addStep(step);
builder.stepdisplay.update();
// Don't immediately stop: this would cause the listener that prevents the click from
// actually activating the selected element to be detached prematurely.
setTimeout(function() { builder.record.stopVerifyExploring(); }, 1);
window.bridge.focusRecorderWindow();
}
);
I destroy the above function by defining stopVerifyExploring to be
builder.record.stopVerifyExploring = function() {
builder.record.verifyExploring = false;
builder.record.verifyExplorer.destroy();
builder.record.verifyExplorer = null;
builder.record.continueRecording();
};
Even after verifyExplorer.destroy is called function(step) is live in anonymous scope and gets executed and does all unwanted things.
I have this weird behavior by replacing
jQuery(frame.document).bind(l, {}, ae.listeners[l], true);
with
frame.document.addEventListener(l,ae.listeners[l],true);
in verifyExplorer. How does me changing the above piece code lead to unexpected behavior?
All this is part of me fixing a bug in an open source project sebuilder. Also related post
The behavior isn't unexpected at all, you've done nothing to cancel the timer.
If you want to cancel the timer, save the return value of setTimeout and then pass that value into clearTimeout later when/if you want to cancel the timer.
What's going on:
Functions and objects exist for as long as anything has a reference to them. When you do:
setTimeout(function() { builder.record.stopVerifyExploring(); }, 1);
...you're saving a reference to that anonymous function in the browser's timer handling stuff. That function has a reference to the context in which it was created (and all containing contexts). So even if you do verifyExplorer = null, that has no effect on anything that the verifyExplorer object used to refer to at all, nor anything that was referring to that object. It just clears the reference to that object from that specific variable. If there are other outstanding references (and there are), the object is kept in memory.
In this case, if the only outstanding reference is the function you've given to setTimeout, then clearing the timeout (probably in destroy) will release the browser's reference to that function, which releases that function's references to the contexts it closes over, and those things are eligible for garbage collection.
More (on my blog): Closures are not complicated
Just wanted to know if it was a good JavaScript practice.
Let's say I have many Web pages that all call an initialization function "init()", would it be the right thing to use an IIFE inside my pattern to run the function everytime the script is loaded?
var foo = (function() {
var bar = "something";
(function init() {
// Do something crazy that's gonna be the same across all my web pages
// like adding an event listener or something
// ...
document.write('page init...');
}());
function privatePage1() {
// This stuff is gonna be used only in page1.html via foo.privatePage1
document.write('page 1' + bar);
}
function privatePage2() {
// This stuff is gonna be used only in page2.html via foo.privatePage2
document.write('page 2' + bar);
}
return {
privatePage1: privatePage1,
privatePage2: privatePage2
}
}());
This is a pretty subjective area, but here's my take:
When you use the module pattern, you're providing a contained set of functionality to the rest of your code. It's essentially a mini-library.
In general, I wouldn't expect a library to do anything when I load it, other than initialization steps that are entirely internal to the library (e.g. setting up the configuration, instantiating a few necessary objects, etc) - nothing that actually affects the DOM or otherwise significantly alters the environment (which is why I've never been entirely comfortable with libraries like Date.js or Prototype that change the prototypes of basic objects).
There are a couple of reasons for this, but the main one is that I don't want to have to worry about the load order of my libraries/modules, other than simply managing dependencies. Independent modules shouldn't affect each other at all. When you manipulate the DOM in your module at load time, sooner or later you'll realize that another piece of your code is expecting the DOM to be in a certain state at a certain time, and that you now have to care about whether you load your module before or after that time. This is an extra bit of complexity that's essentially hidden in the script tag that loads your module.
The other issue here is portability and adaptability. Maybe you'll want to use your module in another project with another DOM setup. Maybe you'll want to pass a different DOM element or config variable to the init() function on a specific page. If you execute init() automagically, you lose the opportunity for configuration.
So what I generally do is to set the init() method as an attribute of the returned module object:
var foo = (function() {
function init() {
// Do something crazy that's gonna be the same across all my web pages
}
//...
return {
init: init,
// etc
}
}());
and then call it as needed elsewhere in my code:
foo.init();
Yes, this adds an extra line of redundant code to the initialization for all my pages (though this is probably just one other script anyway, so the added weight is all of 11 characters). But it allows me a more fine-grained control over when the module is initialized, and offers a hook for configuration arguments when I (inevitably) determine I need them later.
Is the init() function the same across web pages? If so, this is what I'd do:
var foo = (function()
{
init();
return {};
}());
If not, I don't see a reason to use an IIFE, and would simplify your original code like so:
var foo = (function()
{
/* body of the original IIFE here */
return {};
}());