javascript: delete reference to the running code - javascript

I was just wondering if there is any risk when you execute code like this:
window.doSomething = function() {
window.doSomething = null;
// do some stuff here
}
Will this always run fine, or might there be a situation in which the garbage collector will clean it up while it's still running?

window.doSomething = null ;
That will just remove the property doSomething from window which was previously referencing your function.
The function that you're currently in will run until the end, because entering the function increases the reference count, preventing it from being destroyed prematurely.
After the function is done, it will be scheduled for garbage collection.

Related

break out of setInterval loop javascript

I am new to javascript, and I am coding a game.
I would like to break out of the setInterval loop when a condition is met to display a game over screen. My code :
var timer = 0;
var i =0;
fond.onload= function()
{
timer = setInterval(boucle,50);
console.log("break");
}
function boucle()
{
i++;
if(i===4)
{
clearInterval(timer);
}
}
I never reach the break log because just after the clearInterval, the screen is stuck.
Thank you!
I am not sure what fond.onload represents in your code, but if you want the code to run when the page is loaded you should use window.onload or document.onload.
onload is a global event handler bound to all objects that gets executed when that object is loaded. I presume that in your case fond is never loaded as the rest of the code is fine, just never runs. It will run fine if you bind the function to window.onload.
You can read up more on that here

Why is my Web Worker terminated?

I'm trying to get a handle on web workers when I came across a very peculior behaviour. For some reason it's terminated after a few seconds, even though I have code in it that's running.
Here's my code;
Main JavaScript-file:
$(document).ready(function () {
var worker = new Worker("js/TestWorker.js");
worker.addEventListener('message', function (event) {
console.log(event.data);
});
worker.addEventListener('error', function (event) {
console.log(event);
});
});
Worker file:
(function () {
var updateCounter = 0;
var updater = function () {
updateCounter += 1;
console.log("Update counter: " + updateCounter);
postMessage("test");
setTimeout(updater, 10000);
};
updater();
})();
As stated, the worker just stops functioning after a few seconds, 10-20seconds or so.
But if I add this piece of code to my main JavaScript-file;
var check = function () {
var localWorker = worker;
// setTimeout(check, 1000);
};
// setTimeout(check, 1000);
The worker works as intended. The setTimeout-calls aren't needed either, hence why they're commented out. (Note that I can just aswell replace the assignment with worker.length or something similar and it will still work just fine.
Can someone explain this behaviour? Is the worker getting terminated and (erroneously) garbage-collected by the browser or is something else happening here that I'm missing?
Worth to note is that my browser (Chrome) isn't outputing any errors or warnings to the console either.
EDIT: The same behaviour is observed whether the code is executed inside an anonymous function or not.
EDIT2: If I place the worker variable in the global scope it does not get terminated prematurely. What might be the reason for this?
Some research shows that while web workers are supposed to function as you expect (i.e. won't be perceptibly garbage collected), there are some known issues in Chrome which mean you can't rely on that behaviour.
Of specific interest would be this very similar bug: https://bugs.chromium.org/p/chromium/issues/detail?id=572225 which in turn references a more underlying bug: https://bugs.chromium.org/p/chromium/issues/detail?id=572226
It seems to be due to an attempt to garbage collect workers which cannot possibly perform any future activities (in which case the garbage collection would be undetectable, as it's supposed to be), but a flaw in the logic for detecting this state means that any pending activities which aren't directly related to responding to an incoming message will be ignored.
Basically, while you should be able to assume web-workers behave like DOM nodes which can only be removed explicitly, in practice (for now) you need to make sure you always keep a reference to the worker accessible from somewhere, otherwise when the garbage collector kicks in it may kill the worker. This is only necessary if you're using setTimeout or similar in the worker; if it just responds to messages, you won't have a problem.
Maybe worker var must be global
var worker;
$(document).ready(function () {
worker = new Worker("js/TestWorker.js");
worker.addEventListener('message', function (event) {
console.log(event.data);
});
worker.addEventListener('error', function (event) {
console.log(event);
});
});
(function () {
...
})();
This is a anonymous function which will be called once after definition and after that the browser throws it away.
Your web worker is defined it that scope and that's why it's only working for a short period of time.

Does using closure variables in click-functions always result in JavaScript memory leaks?

Given this code:
function init() {
var id = 1234;
$("button").click(function() {
alert(id);
});
}
Basically when init is called it adds a click function on to the button.
Now lets say the button gets removed from the DOM somehow by external code. Normally, from what I understand, the garbage collector will check if the click function can be removed as well.
Will the garbage collector fail to remove the click function since the function is referencing the id variable via a closure, hence creating memory leak or will the click function be removed as well together with the DOM element?
I just tried calling init() ten times to see the memory heap increasing, then I have removed the element to which I have attached the event with the init() function, and as you can see the memory heap does not go down.
I attempted again removing alert(id) from the event and the garbage collector worked this time.

node.js setInterval not working in custom module

I am developing a web application in node.js to collect data from devices on a network using snmp. This is my first real encounter with node.js and javascript. In the app each device will be manipulated through a module I named SnmpMonitor.js. This module will maintain basic device data as well as the snmp and database connection.
One of the features of the app is the ability to constantly monitor data from smart metering devices. To do this I created the following code to start and stop the monitoring of the device. It uses setInterval to constantly send a snmp get request to the device. Then the event listener picks it up and will add the collected data to a database. Right now the listener just prints to show it was successful.
var dataOIDs = ["1.3.6.1.2.1.1.1.0","1.3.6.1.2.1.1.2.0"];
var intervalDuration = 500;
var monitorIntervalID;
var dataCollectionEvent = "dataCollectionComplete";
var emitter = events.EventEmitter(); // Uses native Event Module
//...
function startMonitor(){
if(monitorIntervalID !== undefined){
console.log("Device monitor has already started");
} else {
monitorIntervalID = setInterval(getSnmp,intervalDuration,dataOIDs,dataCollectionEvent);
emitter.on(dataCollectionEvent,dataCallback);
}
}
function dataCallback(recievedData){
// receivedData is returned from getSnmp completion event
// TODO put data in database
console.log("Event happened");
}
function stopMonitor(){
if(monitorIntervalID !== undefined){
clearInterval(monitorIntervalID);
emitter.removeListener(dataCollectionEvent,dataCallback);
} else {
console.log("Must start collecting data before it can be stopped");
}
}
//...
I also have a test file, test.js, that requires the module, starts monitoring, waits 10 seconds, then stops it.
var test = require("./SnmpMonitor");
test.startMonitor();
setTimeout(test.stopMonitor,10000);
My problem is that the setInterval function in startMonitor() is not being run. I have tried placing console.log("test"); before, inside, and after it to test it. The inside test output never executes. The monitorIntervalID variable is also returned as undefined. I have tested setInterval(function(){ console.log("test"); },500); in my test.js file and it runs fine with no issues. I feel like this is a noobie mistake but I just can't seem to figure out why it won't execute.
Here is a link to the entire module: SnmpMonitor.js
I not sure exactly what was wrong but I got it to work by overhauling the whole class/module. I thought the way I had it was going to allow me to create new monitors objects but I was wrong. Instead I created two functions inside the monitor file that do the same thing. I changed the start function to the following.
SnmpMonitor.prototype.start = function() {
var snmpSession = new SNMP(this.deviceInfo.ipaddress,this.emitter);
var oids = this.deviceInfo.oids;
var emit = this.emitter;
var duration = this.intervalDuration;
this.intervalID = setInterval(function(){
snmpSession.get(dataCollectionEvent,emit,oids);
},duration);
};
The setInterval function seems to work best when the callback function is set inside an anonymous function, even though technically you can pass it directly. Using the this. notation I created some class/module/function variables (whatever its called in js) that are in scope of the whole class. For some reason the variables accessed through this. do not work so well when directly in a function or expression so I created temp variables for them. In my other version all the variables were global and js doesn't seem to like that.

Resetting setTimeout object if exists

When somebody clicks my checkboxes, from a long list of checkboxes, I want to show the number of selected checkboxes in a little popup element. My problem is, the little popup element should disappear 5 seconds after the last click, which is OK for one checkbox being clicked, but if I quickly check 5 boxes, the timer is still set on the first box, resulting in the popup element disappearing too quickly.
As you can see in my function, I've tried using the clearTimeout(timeoutName) function but have experienced some troubles applying it. The console log states that the clearTimeout(timeoutName) is undefined, which I can understand: the setTimeout hasn't even started yet.
How can I check that the timer exists before I clear it? Or is this really not the best method? When a checkbox is checked (this function runs) there could be a timer running but sometimes there could not be.
$('.name_boxes').live('click', function() {
var checked_count = $('.name_boxes:checked').length;
// other stuff
clearTimeout(hide_checked_count_timer); // if exists????????
$(".checked_count").hide();
$(".checked_count").text(checked_count+" names selected");
$(".checked_count").show();
hide_checked_count_timer = setTimeout(function() {
$(".checked_count").hide();
},5000);
});
Any help gratefully received...
Just declare the timer variable outside the click handler:
var hide_checked_count_timer;
$('.name_boxes').live('click', function() {
var checked_count = $('.name_boxes:checked').length;
// other stuff
clearTimeout(hide_checked_count_timer); // if exists????????
$(".checked_count").hide();
$(".checked_count").text(checked_count+" names selected");
$(".checked_count").show();
hide_checked_count_timer = setTimeout(function() {
$(".checked_count").hide();
},5000);
});
http://jsfiddle.net/kkhRE/
Considering .live has been deprecated, you should be delegating the event with .on instead:
// Bind to an ancestor. Here I'm using document because it an
// ancestor of everything, but a more specific ancestor
// would be preferred.
$(document).on('click', '.name_boxes', function() {
// ...
});
Q. The console log states that the clearTimeout(timeoutName) is undefined, which I can understand: the setTimeout hasn't even started yet.
A. The clearTimeout() function's return value is undefined regardless of whether there was a timeout to be cleared. It doesn't have a concept of "success" that can be tested. If there is a queued timeout associated with the id you pass then it will be cleared, otherwise nothing happens.
Q. How can I check that the timer exists before I clear it?
You can't, at least not in the sense of there being some registry of outstanding timeouts that you can query. As you already know, the .setTimeout() function returns an id for the timeout just queued, and you can use that id to clear it before it runs, but there is no way to test whether it has already been run. The id is just a number so the variable that you saved it in will continue to hold that number even after the timeout has either run or been cleared.
It does no harm at all to call clearTimeout() with an id for a timeout that already ran - basically if the timeout for that id is in the queue it will be cleared otherwise nothing will happen.
The easiest way to test "Is there an outstanding timeout that hasn't run yet" is to set the variable holding the timerid to null when the timeout runs, i.e., within the function you queued:
var timerid = setTimout(function() {
timerid = null;
// other operations here as needed
}, 5000);
// in some other code somewhere
if (timerid != null) {
// timer hasn't run yet
} else {
// timer has run
}
The variable you save the timerid in needs to be in a scope that can be accessed both where you set it and where you test it, i.e., don't declare it as a local variable within an event handler.
You can use the power of short-circuit operators
hide_checked_count_timer && clearTimeout(hide_checked_count_timer);
The right-hand statement will only run if the left-hand variable is not undefined.
to check if it exists use;
if (typeof timerid == 'undefined')
{
//timer has not been set so create it
timerid = setTimeout(function(){ var something = true;}, 5000);
}

Categories

Resources