What do JavaScript objects outlast and when are they destroyed? - javascript

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.

Related

What are WeakRef and Finalizers in ES2021 (ES12)

I want to understand What are WeakRef and Finalizers in ES2021 with a real simple example and Where to use them.
I know, WeakRef is a class. This will allow developers to create weak references to objects, and Finalizer or FinalizationRegistry allows you to register callback functions that will be invoked when an object is garbage collected
const myWeakRef = new WeakRef({
name: 'Cache',
size: 'unlimited'
})
// Log the value of "myWeakRef":
console.log(myWeakRef.deref())
As always, MDN's docs help.
A WeakRef object contains a weak reference to an object, which is called its target or referent. A weak reference to an object is a reference that does not prevent the object from being reclaimed by the garbage collector. In contrast, a normal (or strong) reference keeps an object in memory. When an object no longer has any strong references to it, the JavaScript engine's garbage collector may destroy the object and reclaim its memory. If that happens, you can't get the object from a weak reference anymore.
In almost every other part of JS, if some object (A) holds a reference to another object (B), B will not be garbage-collected until A can be fully garbage-collected as well. For example:
// top level
const theA = {};
(() => {
// private scope
const theB = { foo: 'foo' };
theA.obj = obj;
})();
In this situation, the theB will never be garbage collected (unless theA.obj gets reassigned) because theA on the top level contains a property that holds a reference to theB; it's a strong reference, which prevents garbage collection.
A WeakRef, on the other hand, provides a wrapper with access to an object while not preventing garbage collection of that object. Calling deref() on the WeakRef will return you the object if it hasn't been garbage collected yet. If it has been GC'd, .deref() will return undefined.
FinalizationRegistry deals with a similar issue:
A FinalizationRegistry object lets you request a callback when an object is garbage-collected.
You first define the registry with the callback you want to run, and then you call .register on the registry with the object you want to observe. This will let you know exactly when something gets garbage collected. For example, the following will log Just got GCd! once the obj gets reclaimed:
console.log('script starting...');
const r = new FinalizationRegistry(() => {
console.log('Just got GCd!');
});
(() => {
// private closure
const obj = {};
r.register(obj);
})();
You can also pass a value when calling .register that gets passed to the callback when the object gets collected.
new FinalizationRegistry((val) => {
console.log(val);
});
r.register(obj, 'the object named "obj"')
will log the object named "obj" it gets GC'd.
All this said, there is rarely a need for these tools. As MDN says:
Correct use of FinalizationRegistry takes careful thought, and it's best avoided if possible. It's also important to avoid relying on any specific behaviors not guaranteed by the specification. When, how, and whether garbage collection occurs is down to the implementation of any given JavaScript engine. Any behavior you observe in one engine may be different in another engine, in another version of the same engine, or even in a slightly different situation with the same version of the same engine. Garbage collection is a hard problem that JavaScript engine implementers are constantly refining and improving their solutions to.
Best to let the engine itself deal with garbage collection automatically whenever possible, unless you have a really good reason to care about it yourself.
The main use of weak references is to implement caches or mappings to large objects. In many scenarios, we don't want to keep a lot of memory for a long time saving this rarely used cache or mappings. We can allow the memory to be garbage collected soon and later if we need it again, we can generate a fresh cache. If the variable is no longer reachable, the JavaScript garbage collector automatically removes it.
const callback = () => {
const aBigObj = {
name: "Hello world"
};
console.log(aBigObj);
}
(async function(){
await new Promise((resolve) => {
setTimeout(() => {
callback();
resolve();
}, 2000);
});
})();
When executing the above code, it prints "Hello world" after 2 seconds. Based on how we use the callback() function, aBigObj is stored in memory forever, maybe.
Let us make aBigObj a weak reference.
const callback = () => {
const aBigObj = new WeakRef({ name: "Hello world" }); console.log(aBigObj.deref().name);}
(async function(){
await new Promise((resolve) => {
setTimeout(() => {
callback(); // Guaranteed to print "Hello world"
resolve();
}, 2000);
});
await new Promise((resolve) => {
setTimeout(() => {
callback(); // No Gaurantee that "Hello world" is printed
resolve();
}, 5000);
});
})();
The first setTimeout() will surely print the value of the name. That is guaranteed in the first turn of the event loop after creating the weak reference.
But there is no guarantee that the second setTimeout() prints "Backbencher". It might have been sweeped by the garbage collector. Since the garbage collection works differently in different browsers, we cannot guarantee the output. That is also why we use WeakRef in situations like managing the cache.
More Information...

Javascript issue because of no weak reference

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.

Javascript object lifecycle

I have a Javascript class like below:
var MYCLASS = function(elem, data, op) {
var options = {};
var loopForEver = function() {
console.log('I cant stop me');
setTimeout(function() {
loopForEver();
}, 1000);
}
this.init = function() {
loopForEver();
}
}
when I instantiate the class and call init function, then the loop starts and I get the text in my console every 1 second :
var ins = new MYCLASS();
ins.init();
Why when I set the instance to null, the thread does not stop? or any time I create a new instance and assign it to the previous instance name, it increases the calls.
in my production code, I do not have infinite loop, but I do have some business logic. do I need to be worried about performance when I create a new instance?
When you call setTimeout it is not bound by the function that called it. You need to add a property to object called something like timeOutID. As long as the function is still required being used by something like setTimeout it will remain in scope.
var MYCLASS = function(elem, data, op) {
var options = {};
var timeOutID = null;
var loopForEver = function() {
console.log('I cant stop me');
timeOutID = setTimeout(function() {
loopForEver();
}, 1000);
}
this.init = function() {
loopForEver();
}
this.stop = function () {
clearTimeout(timeOutID);
}
}
You have a memory leak.
In other words, memory leaks may occur when objects, which are now unreachable, are still kept in memory because they are being referenced somewhere else in the call stack.
Nullifying the instance doesn't clear from memory other references to that object. See this answer to "Can an object automatically delete itself in javascript once it has achieved its purpose?"
In fact, your setTimeout call is repeatedly creating a new execution context each with its own untouchable Activation object, which are unaffected by assigning the original instance to null.
An excerpt from "Understanding delete" (Perfection Kills by kangax) explains it this way:
When a function is executed, it is said that control enters
execution context…; that code might call a function, with its own execution context; that function could call another function, and so
on and so forth.
Even if function is calling itself recursively, a new execution
context is being entered with every invocation.
…when in Function code, a Variable object is … a so-called Activation
object. Activation object is created every time execution context for
Function code is entered.
Note that Activation object is an internal mechanism and is never
really accessible by program code.
If you want to nullify the instance, you should clean it up first by clearing the timed recursive call using .clearTimeout().

How to mark a "new" object for garbage collection in Javascript (Node.js)

If I can't avoid using the "new" keyword in my Node.js app, how can I efficiently mark the object for garbage collection? I create a new object with a fairly high level constructor (by that, I mean new myObj() actually creates several new Something() objects deeper down in the process.
Let's say my constructor looks a little like the following:
function User(name, age) {
this.something = x;
this.greet = function() { return "hello"; };
this.somethingElse = new OtherThing();
return this;
}
Then I create a new User within another function:
function createUserAndGreet(name, age) {
var user1 = new User(name, age);
user1.greet();
// now I don't need user1 anymore
}
(btw, I know this code sucks but I think it gets my point across)
After I have got him to greet, how can I then get rid of him and free up the memory he occupied?
So if I just set user1 to null with user1 = null; after I'm finished with him, will he be gone forever and GC will come and clean him up? Will that also delete the new OtherThing() that was created? Or is there something else I need to do? I hear that using new is notorious for memory leaks so I just want to know if there's a way around this.
The GC takes care of everything that is not referenced. Your code is "GC-Compatible" as is, because after the call to createUserAndGreet(), all references are destroyed.
The only things you have to care about regarding GC is what is attached directly to the Window object (globals), these will never be collected. Your two variables are scoped inside createUserAndGreet() and this scope is destroyed when the function call ends.

Working immediately with instances of asynchronous (dynamically loaded) classes in Javascript

The situation was that I wanted to create an instance of a helper class, but that helper class required initialisation through external scripts, so it was inherently asynchronous. With
var obj = new myObj();
clearly an call to
obj.myMethod();
would yield undefined, as obj would either be empty or undefined until its methods and params were loaded by the external script.
Yes, one could restructure things to have a callback pattern and work with the new object within that, but it gets cumbersome and awkward when working with a large and varied API with many dynamic objects as I've been working with.
My question has been, is there any possible way to cleverly get around this?
I imagine the academically trained programmers out there have a name for this sort of approach, but I put it here in case it's not better written somewhere.
What I've done is modify my loader class to use a placeholder+queue system to instantly return workable objects.
Here are the components. Sorry that there are jQuery bits mixed in, you can easily make this a pure-JS script but I've got it loaded anyway and I'm lazy.
'Client' makes this request, where 'caller' is my handler class:
var obj = caller.use('myObj',args);
In Caller, we have
Caller.prototype.use = function(objname,args) {
var _this = this;
var methods = ['method1','method2'];
var id = someRandomString();
this.myASyncLoader(objname,function(){
var q = [];
if (_this.objs[id].loadqueue) {
q = _this.objs[id].loadqueue;
}
_this.objs[id] = new myRemotelyLoadedClass(args);
//realise all our placeholder stuff is now gone, we kept the queue in 'q'
_this.objs[id].isloaded = true;
//once again, the jquery is unnecessary, sorry
$.each(q,function(a,b){
_this.objs[id][b['f']](b['a']);
});
});
_this.objs[id] = _this.createPlaceholderObj(methods,id);
return _this.objs[id];
}
This function basically initiates the loader function, and when that's done loads a new instance of the desired class. But in the meantime it immediately returns something, a placeholder object that we're going to load with all of our remotely loaded object's methods. In this example we have to explicitly declare them in an array which is a bit cumbersome but liveable, though I'm sure you can think of a better way to do it for your own purposes.
You see we're keeping both the temporary object and future object in a class-global array 'objs', associated with a random key.
Here's the createPlaceholderObj method:
Caller.prototype.createPlaceholderObj = function(methods,id) {
var _this = this;
var n = {};
n.tempid = id;
n.isloaded = false;
$.each(methods,function(a,methodCalled){
n[methodCalled] = function(){
_this.queueCall(id,methodCalled,arguments);
}
});
return n;
}
Here we're just loading up the new obj with the required methods, also storing the ID, which is important. We assign to the new methods a third function, queueCall, to which we pass the method called and any arguments it was sent with. Here's that method:
Caller.prototype.queueCall = function(id,methodName,args) {
if (this.objs[id].isloaded == true) {
this.objs[id][methodName](args);
} else {
if (this.objs[id].loadqueue) {
this.objs[id].loadqueue.push({'f':methodName,'a':args});
} else {
var arr = [{'f':methodName,'a':args}];
this.objs[id].loadqueue = arr;
}
}
}
This method will be called each time the client script is calling a method of our new object instance, whether its logic has actually been loaded or not. The IF statement here checks which is the case (isloaded is set to true in the caller method as soon as the async function is done). If the object is not loaded, the methodName and arguments are added to a queue array as a property of our placeholder. If it is loaded, then we can simply execute the method.
Back in the caller method, that last unexplained bit is where we check to see if there is a queue, and if there is, loop through it and execute the stored method names and arguments.
And that's it! Now I can do:
var obj = caller.use('myObj',args);
obj.someMethod('cool');
obj.anotherMethod('beans');
and while there might be a slight delay before those methods actually get executed, they'll run without complaint!
Not too short a solution, but if you're working on a big project you can just put this in one place and it will pay many dividends.
I'm hoping for some follow-ups to this question. I wonder, for example, how some of you would do this using a deferred-promise pattern? Or if there are any other ways? Or if anyone knows what this technique is called? Input from JS whizzes much appreciated.

Categories

Resources