I've been trying to track down any issues with garbage collection within my application code. I've stripped it down to pure knockout code and there seems to be an issue collecting created objects depending on how a computed property is created.
Please see the following JS fiddle: http://jsfiddle.net/SGXJG/
Open Chrome profiler.
Take a heap snapshot
Click Make All
Take another heap snapshot
Compare the snapshots
Test2 & Test3 still remain in memory while Test1 is correctly collected.
Please see the following code for the viewmodel:
function ViewModel() {
this.test1 = null;
this.test2 = null;
this.test3 = null;
}
ViewModel.prototype = {
makeAll: function () {
this.make1();
this.make2();
this.make3();
},
make1: function () {
this.test1 = new Test1();
this.test1.kill();
delete this.test1;
},
make2: function () {
this.test2 = new Test2();
this.test2.kill();
delete this.test2;
},
make3: function () {
this.test3 = new Test3();
this.test3.kill();
delete this.test3;
},
};
ko.applyBindings(new ViewModel());
And here are the three tests classes:
function Test1() {
var one = this.one = ko.observable();
var two = this.two = ko.observable();
this.three = ko.computed(function () {
return one() && two();
});
}
Test1.prototype = {
kill: function () {
this.three.dispose();
}
};
function Test2() {
this.one = ko.observable();
this.two = ko.observable();
this.three = ko.computed(function () {
return this.one() && this.two();
}, this);
}
Test2.prototype = {
kill: function () {
this.three.dispose();
}
};
function Test3() {
var self = this;
self.one = ko.observable();
self.two = ko.observable();
self.three = ko.computed(function () {
return self.one() && self.two();
});
self.kill = function () {
self.three.dispose();
};
}
The difference being that Test1 'three' computed does not use this or self to reference the 'one' & 'two' observable properties. Can someone explain what's happening here? I guess there's something in the way the closures contain the object reference but I don't understand why
Hopefully I've not missed anything. Let me know if I have and many thanks for any responses.
Chrome, like all modern browsers, uses a mark-and-sweep algorithm for garbage collection. From MDN:
This algorithm assumes the knowledge of a set of objects called roots (In JavaScript, the root is the global object). Periodically, the garbage-collector will start from these roots, find all objects that are referenced from these roots, then all objects referenced from these, etc. Starting from the roots, the garbage collector will thus find all reachable objects and collect all non-reachable objects.
The garbage collector doesn't run right away, which is why you still see the objects in Chrome's snapshot even though you've dereferenced them (edit: As mentioned here, running the heap snapshot first runs the garbage collector. Possibly it's not processing everything and so doesn't clear the objects; see below.)
One thing that seems to generally trigger the garbage collector is to create new objects. We can verify this using your example. After going through the steps in your question, click on "Make1" and take another heap snapshot. You should see that Test2 is gone. Now do it again, and you'll see that Test3 is also gone.
Some more notes:
Chrome doesn't clean up everything during garbage collection. "[Chrome]...processes only part of the object heap in most garbage collection cycles." (google.com) Thus we see that it takes a couple runs of the garbage collector to clear everything.
As long as all external references to a object are cleared, the object will be cleaned up by the garbage collector eventually. In your example, you can even remove the dispose calls, and all the objects will be cleared.
I think this is a classical loop reference problem.
Let's call:
var test2 = new Test2();
now test2.three holds a reference of test2! Because you literally asked knockout to bind a function(){...} with that "this" object, the test2 object.
Since test2 naturally holds a reference of test2.three, you now got a loop reference between the two objects!
You can see this is same for your Test3.
But for Test1, let's call:
var test1 = new Test1();
test1.three holds references of two objects (test1.one and test2.two), test1 holds three references (test1.one, test1.two and test1.three), there is no loop reference.
In some other languages like Java and Objective-C, the language supports weak reference to deal with this kind of issue. But so far, weak reference not implemented in Javascript.
+1 thanks for your question! It gave my brain some spin, helped me to understand Javascript more :)
I think the problem is that you use && in your code, it will return a boolean, properly "true".
this.three = ko.computed(function () {
// !
return this.one() && this.two();
},
So this.three == true and not self.one + self.two if this was the intention?
and when you dispose
this.three.dispose();
You just get rid of a boolean.
Is there a reason why you have an extra "this" in "function Test2()"?
Related
I have a function im trying to test:
vm.clearArray = function(){
for (var id=0; id<vm.copyArray.length;id++){
vm.styleIcon(vm.copyArray[id],'black')
}
vm.copyObjArray = [];
vm.copyArray = [];
}
I'm trying to test it like:
it('should have cleared copyArray on function call', function(){
var ctrl = $componentController('copy', null);
spyOn(ctrl, 'clearArray').and.callThrough();
spyOn(ctrl, 'styleIcon').and.callThrough();
ctrl.copyArray = [123];
ctrl.clearArray();
expect(ctrl.clearArray).toHaveBeenCalled();
// expect(ctrl.styleIcon).toHaveBeenCalled();
expect(ctrl.copyObjArray).toEqual([]);
expect(ctrl.copyArray).toEqual([]);
});
If I uncomment the above expect I get an error and the vm.styleIcon call is never covered in my coverage report. By setting copyArray to contain a value in the array I would think that the for loop would then trigger when running the test. That does not seem to be the case.
Thanks.
I believe there is some kind of inheritance scheme that is causing your error. My assumption is that your controller is extended by a base controller.
From what few code I see, I can make two assumptions:
1) clearArray() is overridden in the child controller eg.
vm.clearArray = function(){
...
vm.copyArray = [];
}
so you are trying to test the wrong clearArray()
or
2) ctrl.copyArray is not writable because of the way inheritance was implemented, eg.
function ParentController() {
var vm = this;
vm.copyArray = [];
vm.copyObjArray = [];
vm.clearArray = function() {
for (var id=0; id<vm.copyArray.length;id++){
vm.styleIcon(vm.copyArray[id],'black')
}
vm.copyObjArray = [];
vm.copyArray = [];
}
vm.styleIcon = function(index, color) {
}
};
function ChildController() {
ParentController.call(this);
}
ChildController.prototype = Object.create(ParentController.prototype, {copyArray:{ value: [] } });
var ctrl = new ChildController();
Using the above will yield the error, copyArray is defined as a non writable property, so line:
ctrl.copyArray = [123];
does not change its value.
Object.defineProperty()
Difference between Configurable and Writable attributes of an Object
Anyway, without more of the code, it is difficult to get what is causing the error.
The code of the loop looks good, so I think that the property vm.copyArray might not be set at all. If you add a console.log(vm.copyArray), what is the result?
Perhaps vm and $componentController('copy', null) are not references to the same object, but call each other's functions through some library? is there any other way to reference vm from the test script, rather than using $componentController('copy', null)?
Your loop must be triggered when you pass the array in the function as an argument. Of course your actually code will fail unless the pass vm.copyArray as an argument in the actual code, but it will show you if the loop is the problem, or the reference to the vm from the test script:
//tested function
vm.clearArray = function(copyArray){
for (var id=0; id<copyArray.length;id++){
vm.styleIcon(copyArray[id],'black')
}
}
//test
ctrl.clearArray([123]);
It's difficult to determine the exact reason because you've shown a sample taken straight from your test, and not a minimal, complete, and verifiable example. Also, you didn't specify what the error(s) or expect results are, so we're going off very limited information.
That said, I strongly suspect vm is undefined/null or not a prototype instantiatable through $componentController. If this is the case, you should be receiving an error at spyOn(ctrl, 'clearArray').and.callThrough() or ctrl.clearArray(), never running the loop and thus never calling vm.styleIcon. In this scenario you'd need to verify that ctrl is in fact an instance of whatever prototype vm is a part of(is it actually a global variable?).
If this is not the case and both the vm prototype is correct and $componentController('copy', null); is creating the object you think it is, perhaps styleIcon is undefined/null, unable to be called and creating essentially the same problem. In this scenario, ensure styleIcon is set and that it's the function you think it is.
When all else fails, debuggers are your friend.
Please specify what the error(s) are and where they're occuring(in more detail) for a better answer.
I've got 3 codes :
var control = new Control();
function Control() {
this.doSomethingElse = function() {...}
this.doSomething = function () {
control.doSomethingElse();
}
}
Or
var control = new Control();
function Control() {
var self = this;
this.doSomethingElse = function() {...}
this.doSomething = function () {
self.doSomethingElse();
}
}
Or
var control = Control();
function Control() {
var self = this;
this.doSomethingElse = function() {...}
this.doSomething = function () {
self.doSomethingElse();
}
return self;
}
Important : The function is a controller, and just declared once. Then I'm using "control" everywhere in my code...
I was wondering if the control.doSomethingElse() was slow ?
In the end, what is the right thing to do and/or the fastest code in those exemple ?
Thanks !
The first is wrong - an object should never internally use the variable name by which it is known outside. Other code could change that variable to point to something else, breaking this code.
The third is also wrong - when calling Control() without new the assignments to this.foo inside will end up getting attached to the global object (except in strict mode, where there's no implicit this on bare function calls, so the assignment to this.doSomethingElse tries to attach to undefined, causing a runtime error).
That only leaves the second as appropriate, but ultimately it's a question of correctness, not performance.
Do not define methods in constructor - that means defining them every time an instance is created. Use Control.prototype.foo = function() {} instead. Also you do not need to return this if you're using new operator - that's the whole point of new operator.
The recommended approach is this:
function MyClass(param1) {
// Here we're changing the specific instance of an object
this.property1 = param1;
}
// Prototype will be shared with all instances of the object
// any modifications to prototype WILL be shared by all instances
MyClass.prototype.printProperty1 = function() {
console.log(this.property1);
}
var instance = new MyClass("Hello world!");
instance.printProperty1(); // Prints hello world
To understand this code, you need to understand javascript's prototype-based inheritance model. When you create instance of MyClass, you get a new object that inherits any properties present in MyClass.prototype. Read more about it.
Also I wonder:
The function is a controller, and just declared once.
If you're not using this multiple times, you don't need to create something like class. You can do this instead:
var control = {doSomething:function() { ... }};
I assume you are used to Java, where everything must be a class, whether it makes sense or not. Javascript is different, you can also make single objects or functions as you need.
I'm trying to find a simple way to refer to the current instance of an object from the object methods itself (similar to this keyword in any decent language).
I've tried many variations of "storing a pointer for itself" (like window.window.window do), but always something go wrong. For example:
function ClassA() {
var mySelf = this;
this.myMethod = function() {
console.log(mySelf); //Once you extend this class, mySelf will not be available
}
}
function ClassB() {
this.mySelf = this; //Ok, now you can extend this and mySelf will be there
this.myMethod = function() {
console.log(mySelf);//"mySelf is not defined" because it's a property now
console.log(this.mySelf);//Value of 'this' and 'self' will vary
console.log(RandomContainer.ClassBInstance.mySelf);//I can't use a defined path
}
}
Since everything about OOP in JavaScript is hackish, I have to ask...
Is there any magic to refer to the current object that a method is being called from?
EDIT
A lot of possible solutions in the comments, thanks guys!
But I still need to improve my question. So I'll add some piece of code with my failed attempts, and then try out the proposed solutions...
function BaseController()
{
var myPriv = 42;
return {
getAnswer: function() {
return myPriv;
}
};
}
function SomeController()
{
return {
showAnswer: function()
{
var answer;
answer = myPriv; //I need some way to access this
answer = getAnswer(); //Also a way to refer to my own methods
//(I don't even find a way to call 'showAnswer' from this context)
console.log('The answer is ' + answer);
}
};
}
//That's how I was extending my classes so far...
var someControllerInstance = jQuery.extend(
new BaseController(),
new SomeController()
);
someControllerInstance.getAnswer(); //Works!
someControllerInstance.showAnswer(); //Reference errors...
take time to learn the idiosyncrasies of js, be warned though, it's like marmite.
If you'll allow me to be blunt for a moment, you are approaching JavaScript with the wrong frame of mind. It is not designed for classical inheritance, nor for protected properties or methods, and there is no benefit in bending it that way. To be honest I find towering stacks of inheritance a pain to read and navigate, unless you have a singing-all-dancing IDE that may take a week to load. The closer to flat and open you can achieve — whilst still keeping things flexible — the better you are at coding, and the more other coders that may take over your work will thank you. (obviously that is opinion)
For more information on prototype inheritance read the following informative post:
http://davidwalsh.name/javascript-objects-deconstruction
Below is an example of prototype inheritance, it should be noted that Object.create and isPrototypeOf are relatively new and do not exist for older JavaScript interpreters. Approximate polyfills can be used in most cases however.
Put simply JavaScript becomes much more powerful when you think in terms of objects borrowing methods from wherever they may be found, and not instances rigidly inheriting from slightly less specific instances; or worse, constructors that keep rebuilding the same functions again and again.
The following is just an example, and across my 16 years of coding ECMAScript I have barely ever needed anything that approaches classical inheritance, nor have I needed objects that heavily inherit on the prototype chain either. More often than not my js is basically just a number of newly created objects, properly name-spaced, that borrow methods from fixed pools of functions; any type detections are duck-typed, and I'm careful to keep everything as local as possible.
Anyway, here's something I don't often use:
var Make = function(construct){
return Object.create(construct);
};
var Extend = function(proto, props){
var instance = Object.create(proto);
for ( var i in props ) { instance[i] = props[i]; }
instance.super = proto; // this should never be needed really
return instance;
};
var Animal = {
keepBreathing: function(){
console.log('animal', this);
}
};
var Monkey = Extend(Animal, {
climbTree: function(){
console.log('monkey', this);
console.log('monkey', this.super);
}
});
var KeyserSoze = Make(Monkey);
KeyserSoze.keepBreathing(); /// animal, instance of KeyserSoze
KeyserSoze.climbTree(); /// monkey, instance of KeyserSoze
console.log('an instance of monkey', KeyserSoze);
console.log('has animal as proto', Animal.isPrototypeOf(KeyserSoze)); // true
console.log('has monkey as proto', Monkey.isPrototypeOf(KeyserSoze)); // true
Whilst the above does follow a kind of classical layout i.e. Monkey inherits methods from Animal, you could approach things in a different way. The following is more open to dynamic changes, in the fact you could switch out the behaviours object for another interface entirely. Again, this is just an illustration that you don't have to construct things in a fixed way.
Something I'm more likely to use:
var AnimalBehaviours = {
keepBreathing: function(){
(this.breathCount === undefined) && (this.breathCount = 0);
this.breathCount++;
}
};
var ApeLikeDescendant = (function( behaviours ){
return {
create: function( config ){
return Object.create(this).prep(config);
},
prep: function( config ){
/// do your instance specific set up here
return this;
},
climbTree: function(){
console.log('ape-like', this);
},
keepBreathing: function(){
return behaviours.keepBreathing.apply(this, arguments);
},
switchBehaviours: function(newBehaviours){
behaviours = newBehaviours;
}
};
})(AnimalBehaviours);
var DouglasAdams = ApeLikeDescendant.create({});
You could adapt the above to behave more in a manner similar to mixins i.e. you'd take the behaviours, step through them and merge them to the ApeLike object... it's really quite open to whatever your goal is.
Something that I use regularly:
var ElementEdgeCases = {
makeWorkOnNetscape47: function(){
this.target; /// Intentionally left almost blank.
}
};
var ElementFinagler = (function(){
var finagle = {
target: null,
prep: function( element ){
this.target = element;
return this;
},
addClass: function(){
var c = this.target.getAttribute('className'); /// and so on ...
return this;
},
elaborate: function( mixin ){
for ( var i in mixin ) {
if ( mixin.hasOwnProperty(i) ) {
this[i] = mixin[i];
}
}
return this;
}
};
return function( element ){
return Object.create(finagle).prep(element);
};
})();
var elm = document.getElementsByTagName('body')[0];
ElementFinagler(elm)
.elaborate(ElementEdgeCases) // extend the object if we need
.addClass('hello world')
;
The main thing to keep in mind with JavaScript is that no function is owned by anything, not really. Every time you execute a function, the function's context is implied by the way you call that function — the context is computed at call time. This allows a great deal of flexibility, and whilst you mention that calling function.apply(context, args) or function.call(context, arg, arg, ...) every time is cumbersome; it is very easy to codify your own system for hiding that repetition away.
Oh, and before I forget, one other thing to take away from the code above is that there is no duplication of function creation. Every instance shares the same functions in memory. This is an important thing to bear in mind if you are planning to create large scale applications, as you can quickly eat up memory with multiple instances of functions.
So just to recap:
Forget inheritance, it's rarely required for many js projects.
Create flexible objects that can be extended when required.
Borrow methods when you need them from other objects, using apply or call to change context.
Keep your code open, there is no need for private; open is more extensible.
Private no, but having properties not enumerable is a different story, see defineProperty.
Make sure you do not duplicate functions — unless you have to — instead create them once and reference.
this referrers to the dom node that an event originated from, or the javascript object it is a child of. In that order.
this.parentNode referrers the dom node's parent (Not sure if it works in object context).
When I write javascript I'll usually try to leverage the html's dom itself, nesting things mindful of how the JS needs to reference them.
I'm quite new to Javascript and I was just reading following article.
you can define an ajax connection
once, and reuse it multiple times, and
start and stop it later on. Here's an
example:
var myAjaxRequest = A.io.request('test.html', {
method: 'POST',
data: {
key1: 'value1'
}
});
Now later on, if I want to make that
same ajax call again, all I have to do
is call:
myAjaxRequest.start();
What if I had a very frequently used auction page and I wanted to use the myAjaxRequest connection for all actions a user does from his browser. What are the rules for lifetime of the myAjaxRequest instance ? I suppose it is destroyed on page refresh. But is it anything else that destroys it ? Let say that the object is created within YUI sandbox, but it doesn't matter.
Its a shame this was answered in comments because nobody gets closure (sorry, terrible pun). #Šime Vidas and #WaiLam deserve the credit but I will at least attempt to craft an answer:
While you have a reference to the object (though the variable myAjaxRequest) it will remain in memory until the document is unloaded. If you assign null to your variable (myAjaxRequest = null), and there are no other references to the object, then the garbage collector will reclaim the memory used to store it.
A reference can exist even if myAjaxRequest is a local variable within a function. The function can return a reference to the local variable, for example as a object property e.g:
function sandbox () {
var myAjaxRequest = A.io.request(/* constructor... */);
return {
myRequest: myAjaxRequest
};
}
var mySandbox = sandbox();
mySandbox.myRequest.start();
or it can return a reference through a closure (excellent explanation here), e.g:
function sandbox () {
var myAjaxRequest = A.io.request(/* constructor... */);
return {
getRequest: function () {
return myAjaxRequest;
}
};
}
var mySandbox = sandbox();
mySandbox.getRequest().start();
As long as you have a reference to your object it will not be garbage collected. You can safely call the start method until the page is unloaded.
In JavaScript, I know that a closure is can be defined as a nested function that has access to its containing function's variables. For example:
function outerFunction(x, y) {
function innerFunction() {
return x + y + 10;
}
return innerFunction;
}
Now, the following code is wiring up a callback for the onreadystatechange property of the request object; however, I was wondering if, by definition, this is also considered to be a closure:
/* This is a contrived example, I know.
* Bear with me - it demonstrates the point I'm trying to convey. */
function submitHandler() {
var oRequest = createRequest(); // assume I'm getting an instance of the xhr
var sUsername = 'Tom'; // assume this is needed for work in the handler
var This = this;
oRequest.onreadystatechange = function() {
This.handleResponse(oRequest, sUsername)
}
}
function handleResponse(oResponse, sUsername) {
if(oResponse.readyState === 4 && oResponse.status === 200) {
// do work with the username
} else {
// we're not done yet...
}
}
I realize that the handleResponse function could also just be written as an anonymous function in the context of submitHandler, but I find that more complex Ajax code can be more readable and easily maintained if callbacks are defined outside the scope of the function calling back to them. Again, this is a contrived example that I'm using in hopes of simply demonstrating the point of my question.
Yes, you are correct in assuming that it is a closure by definition.
It sounds like you know your stuff but here is a good, extensive article on javascript closures.
I wholeheartedly agree that too many inline closure functions don't enhance readability. On the other hand I strongly dislike the var self = this style of writing closures, to which this is just a variant, as it's still too verbose in its declaration, and you introduce your own new 'keyword' whether that is this or self.
What you want is to curry/bind the method.
function $A(o)
{
var a = [];
for (var i = 0; i < o.length; ++i)
a.push(o[i]);
return a;
}
Function.prototype.bind = function()
{
var _method = this;
var a = $A(arguments)
var o = a.shift();
return function()
{
return _method.apply(o, a.concat($A(arguments)));
}
}
Function.prototype.curry = function()
{
var _method = this;
var a = $A(arguments);
return function()
{
return _method.apply(null, a.concat($A(arguments)));
}
}
The methods are taken from the Prototype library. I use these even in projects that don't use the Prototype library as they are very useful!
In your case this means instead of writing:
var This = this;
oRequest.onreadystatechange = function() {
This.handleResponse(oRequest, sUsername)
}
you can now write:
oRequest.onreadystatechange = this.handleResponse.curry(oRequest,sUsername);
However if you want to transfer the meaning of the this keyword you could do this
oRequest.onreadystatechange = this.handleResponse.bind(this,oRequest,sUsername);
handleResponse, when called, will have the same this context as the submitHandler.
Your first example is not a closure. It would have been had you returned innerFunction but you are executing the innerFunction and returning the result.
The second example works and is using a closure. One caveat with this specific technique is that you can end up with quite a severe memory leak in some browser implementations (IE certainly and may be others). You will have created a circular reference between the xhr held in oRequest, the onreadystatechange referencing a function and that functions scope being the scope where the xhr is held. Not only will the xhr remain in memory so will the response which if large (and especially if XML) can gobble memory quickly.
Set the onreadystatechange property to an empty global level function during the handling for the response. This will break the circle.