Tool to see object references - javascript

Is there a tool for Node.js or the browser whereby I can find out which objects hold a reference to object X?
Right now I am using Backbone for front-end development and even though I remove views there still seem to be references to them afterwards.
The reason I suspect this behavior in the first place is because I am using plugin/addons for Backbone debugging in Chrome and Mozilla.
This does make me wonder if perhaps these programs themselves are the ones holding references to the Backbone objects!

First of all,Sadly there is no way to do that.
You can check who calls a function and object which specific variable holds as reference though.
It's not because of Backbone/Node.js but Javascript itself.
When you substitute object/Array, javascript only passes target memory address to the variable.
But I assume it's highly possible that the reason why you are having memory leak problem is not because of references from another variables but event handlers which is often seen in Backbone uses(also knowns as "zombie view")
Once you set events handler in a View, You need to make sure all events are unset before you actually delete the view(.remove()) unless You are using only listenTo for Backbone events and this.$el for jQuery events.
Because events set via listenTo and this.$el are automatically removed by Backbone Core when you remove a View.
And events set by Model.on or global jQuery$ would not be so.
So Please check your whole code whether You are using .on or global jQuery Object to set events, in the case You have, replace them into listenTo or this.$el.on or manually unset them Before You remove them.

Related

Listen for window events or attach objects to window

I have an object, which I need to control from another object.
What's a better practice and why?
Reference the object by window.object = this in it's constructor and then call window.object.method() from the other one
or
Start listening like $(window).on 'objectEvent' and triggering the event from the other object like $(window).trigger('objectEvent')?
I am currently using the second approach, but I'm wondering, whether it's the right one.
The second approach is the least bad. You want to avoid polluting the global namespace, ie: adding properties to window.
In the second case you are adding listeners to it, which isn't that bad if you namespace event names, but the best option would be to use an intermediary object and implement the Pub/Sub pattern, so both objects interact b/w themselves through it.

What does backbone.js do with models that are not used anymore

Lately I am diving into the whole client-side MVC/MVVM design paterns, and the one I am particularly interested in is backbone.js.
One thing I do not fully understand is what happend to the models when they are not really needed anymore.
Let's say we have an app that has users and products. We have user models/views and product models/views
NOTE: for simplicity sake we are not a user. We can just CRUD users / products.
When I enter the products page, I assume we load the model and the view corresponding to this.
What happens when we leave the page and enter the users page. A user model/view is loaded, but the products are also still loaded.
Do we keep them loaded, does backbone take care of that for you, or do you explicitly need to end certain objects.
Backbone does not explicitly handle cleaning up objects for you. It's 50/50 you and the JavaScript runtime.
JavaScript is a garbage collected language like Java, C#, Ruby, and others. The basic of a garbage collected languages is that an object that is still referenced by your application will not be cleaned up. The counter to that is when an object is no longer referenced by your application, will be cleaned up.
JavaScript in general:
When you create a variable, you can either scope that variable to a local function or as a global variable.
Global variables are never cleaned up by the garbage collector, during the life of the page. The only time they are cleaned up is when you leave the HTML page behind entirely - navigate to a different page and force the browser to load the new page from the server (doing a complete server refresh) or closing the browser or browser tab.
Function scoped variables are cleaned up when the variable falls out of scope - that is, when the function has exited and there are no more references to it. There are a few exceptions to this: return values and closures.
A return value is held in your app by assigning the return value to another variable. A return value falls under the same general rules, but the variable is now in a different function. Once that variable goes out of scope, it can be cleaned up.
A closure allows a parent scope to provide values that a descendant scope can access. When the descendant scope is cleaned up, the parent's closured variable may be allowed to be cleaned up (assuming nothing else is holding on to it).
Objects with attributes and functions fall under the same rules. An object can reference another object or function by having an attribute assigned to it: myObj.foo = thatObj.
The DOM (Document Object Model - the HTML in your app) is a JavaScript object. Events and other references to your DOM work the same as any other reference. If you have an object handling a DOM event, it has a reference in your app and it won't be cleaned up by the garbage collector. If you want it cleaned up, you have to remove all references to it - including the DOM reference from the event handler.
Cleaning Up Memory
The general rule is that if you are loading data in to a backbone collection or object and you want that object to be cleaned up so it's not using anymore memory, you must remove all references to that object. This is just the standard JavaScript garbage collection rule.
You cannot force garbage collection, but you can force a variable to de-reference the thing it points to using the delete keyword in JavaScript: delete myVar
Backbone
Backbone is JavaScript so it falls under the same rules. There are some interesting uses of closures and references in Backbone that you need to be aware of, which will help you to know when you need to manually clean up some objects.
For example: events. An even handler / callback method works by having a reference between the object that triggers the event and the callback that handles the event. This is one of the easiest places to cause memory leaks in a Backbone app and I discuss it in detail, here: http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/
Other than being aware of how events work in terms of references, just follow the standard rules for manage memory in JavaScript and you'll be fine. Once you remove all references to that collection of User objects, they'll be cleaned up.
Note that if you console.log() your model (at least in Chrome) it will remain in memory because the console has a reference to it.
I got mad because of this. If you see memory leak, try clearing your console and run your profile again. If you had the same problem i had, it's gone :)

Where is my YUI 3 instance living? (plus some YUI event observation)

This question is mostly just out of academic interest.
I started using YUI 3 today and came across its sandbox concept. After thoroughly trying to find some objects (like my registered event handlers) inside the DOM I had to give up. I just couldn't find any instance objects ending up there.
I think I have closures mostly covered: even if the sandbox heavily relied on them, there would have to be at least one visible reference anywhere at least to parts like event handlers (else nobody could access anything and even closures would be garbage collected at some time in that case), right?
Where can I find the YUI instance inside the DOM (w/out assigning it to a global variable)?
Can I find it: are sandboxed YUI objects or parts of them living inside the DOM at all?
Getting more specific (and slightly off-topic) with an example:
I have a YUI Node object with attached YUI widgets and events. These Node objects are wrapping DOM nodes. Inspecting the DOM the wrapped nodes don't have any observers.
How are the events attached to the Node object triggered if nothing is wired up inside the DOM?
The only visible references with YUI 3 are the YUI global object and occasional element id that is assigned by YUI. Event subscriptions are made with native addEventListener or attachEvent, which don't leave evidence in the markup or innerHTML. There are some developer tools that are capable of showing subscriptions attached in this way, though, and they would show the YUI subscriptions.
You cannot find the YUI instance inside the DOM. That's the point of sandboxing. Instances of YUI exist in the JavaScript layer (technically, ECMAScript layer), not the DOM layer, exclusively inside closures unless you expressly assign them to a globally accessible variable or property or a globally accessible variable.

Should you dispose of jQuery objects?

A colleague of mine always sets their jQuery variables to null, to effectively dispose them, once they're finished with, e.g:
var bigThing = $(body);
// ...
// Do some stuff
// ...
bigThing = null;
Is that really necessary?
If you encapsulate your code into functions thats unnecessary as after the function finishes the local variables will be killed anyway when no reference of them is used elsewhere.
Holding onto a selector/variable (caching) might have some positive effect tho if you need to select the same thing over and over again versus selecting it only once and keeping the variable.
Short answer: no that's hardly ever necessary if you're using jQuery.
It depends on what you did with it. If you didn't attach any event handlers to the DOM Node, the garbage collector will clear it when it's no longer referenced.
But even if you did attach event handlers, jQuery will take care of them in functions like .remove() and .empty() by detaching all event handlers for you. So as long as you use jQuery to interact with the DOM, you're safe.
Without jQuery, if you've attached an event handler to the Node, the GC won't clear it, even after you've removed the Node from the DOM tree and you no longer have any references to it. This is because the DOM Node contains a reference to a JavaScript object (i.e. the event handler) and vice versa. This creates a cyclic reference across two separate systems; something most garbage collectors have trouble with.
For further reading I point you to Douglas Crockford's article on Memory Leaks.
It's not necessary but good habit to remove reference and release the memory
Though not entirely necessary, this can be done to ensure that the GC clears it in its next run (which it'll anyway do for all allocations to which you don't have even 1 reference).
In your example though, the $(body) object (the jquery extended object, not the DOM body object) will be cleared if you set bigThing to anything else (not necessarily null)
Javascript has its own garbage collector. So, it appears that you don't need to explicitly dispose of the objects.
But due to various reasons, like bad implementation of garbage collector etc., it may happen that their are some memory leaks.
By nullifying them explicitly, you specify to the browser that this memory has to be cleared in next garbage collection.
In conclusion, though it is not necessary to do this, it will be a good practice to nullify the JQuery/javascript objects.

jQuery.data no longer works with window?

I recently upgraded our project's jQuery file from 1.4.2 to 1.4.4 and it appears that as of 1.4.3 the way we have been using jQuery.data has stopped working.
We have this code:
var events = $(window).data('events');
if (events.scroll)
if (!events.scroll.include(handler))
$(window).scroll(handler);
the purpose is to prevent this particular handler from being bound multiple times.
In 1.4.2, this works fine. In 1.4.4, events is undefined.
function handler() {
//do something
}
$(document).ready(function(){
$(window).scroll(handler);
$('div#test').scroll(handler);
$(window).data('events') -> undefined
$('div#test').data('events') -> Object
});
What changed with this API? How should I list events for window?
I have changed the first line to this:
var events = $(window).data('__events__').events;
a bit messy-looking, but the ability to wire events to plain objects is compelling.
There was a change in jQuery 1.4.3+ for event types, to avoid object name collisions, for window (or any other plain object) use the key "__events__" instead, like this:
var events = $(window).data('__events__');
The same __events__ key is used for any objects that don't have a .nodeType property (which window doesn't, so it's treated like a plain object here).
To be clear that this was a conscious, intentional change, it's included in the jQuery 1.4.3 release notes:
JavaScript Objects
A number of changes were made to when .data() is used on JavaScript objects (or, more accurately, anything that isn’t a DOM node). To start whenever you set data on a JavaScript object the data is set directly on the object – instead of going into the internal data object store. Additionally events that are attached to objects are put in a new __events__ property that is actually a function. This was done to allow events to be attached directly to an object, be garbage collected when the object is collected, and not be serialized by a JSON serializer. These changes should make jQuery’s data and event systems much more useful on JavaScript objects.
The basic API still seems to work.
However, it doesn't seem to work on the window.
So, the API for accessing jQuery-assigned events hasn't really changed; it just no longer applies to the window. That doesn't exactly sound like an intentional decision, and the 1.4.3 -> 1.4.4 changelog makes no mention of it.
Sounds like a bug, and it might have to do with the recent changes to data now being able to access HTML5 data- attributes. Consider filing a ticket for it :/

Categories