So I have this function that executes on setTimeout and console.log returns the correct value for the variable I named time however the function is running with no delay when I run the code. The code is server side for a game I am making. The code is supposed to gradually restore health to the player after using an item. My issue is with the settimeout function... also it works when I use it in the browser but not from my node console.
function balm(i){
this_sql ="UPDATE game_moblist SET hp = least(max_hp, hp +"+Math.round(i/2)+") WHERE id ="+mobid;
connection.query(this_sql, function(err, rows, fields) {
if (err) err=null
});
console.log(this_sql);
this_sql = "SELECT hp, max_hp FROM game_moblist WHERE id ="+mobid; //emite catch all update pointint to hp..
connection.query(this_sql, function(err, rows, fields) {
if (err) throw err;
socket.emit ('updatemisc',handler,rows);//eval handler using args
if (rows[0].hp==rows[0].max_hp){
i=0;
return i;
}
});
}
for (i=30;i>=0;i--){
time=(31-i)*1000;
console.log(time);
setTimeout(balm(i),time);
}
So I have this function that executes on setTimeout and console.log returns the correct value for the variable I named time however the function is running with no delay when I run the code. The code is server side for a game I am making. The code is supposed to gradually restore health to the player after using an item. My issue is with the settimeout function... also it works when I use it in the browser but not from my node console.
function balm(i){
this_sql ="UPDATE game_moblist SET hp = least(max_hp, hp +"+Math.round(i/2)+") WHERE id ="+mobid;
connection.query(this_sql, function(err, rows, fields) {
if (err) err=null
});
console.log(this_sql);
this_sql = "SELECT hp, max_hp FROM game_moblist WHERE id ="+mobid; //emite catch all update pointint to hp..
connection.query(this_sql, function(err, rows, fields) {
if (err) throw err;
socket.emit ('updatemisc',handler,rows);//eval handler using args
if (rows[0].hp==rows[0].max_hp){
i=0;
return i;
}
});
}
for (i=30;i>=0;i--){
time=(31-i)*1000;
console.log(time);
setTimeout(balm(i),time);
}
Share
Improve this question
edited Sep 30, 2016 at 11:49
Ricardo Rodrigues
1337 bronze badges
asked Jul 5, 2012 at 22:05
ShawnShawn
9112 gold badges12 silver badges23 bronze badges
2 Answers
Reset to default 6The problem is here:
setTimeout(balm(i),time);
What that does is call balm
and feed its return value in to setTimeout
, which isn't what you want. You want to pass setTimeout
a function that, when called, will call balm
with a given i
value. You do that like this:
setTimeout(makeHandler(i),time);
function makeHandler(index) {
return function() {
balm(index);
};
}
That way, the balm
function gets called later, and gets called with the i
value as of when the timeout was scheduled. Without the makeHandler
thing, all balm
instances would see i
as it was when they ran (e.g., they'd all see -1
). This is because in JavaScript, a closure has enduring access to the variables in context; not a copy of them when the the closure was created. So all of them see the current value of i
. (More: Closures are not plicated)
(Note that on NodeJS — the environment you're using — and also on Firefox, you can use the non-standard extension to setTimeout
that allows you to give arguments to pass to the function; see pksunkara's answer. But for anyone looking to do this client-side on the web [rather than server-side with Node], beware, that is not standard.)
To illustrate this, here's an example (this one runs in a browser, but it's the same for server-side stuff like NodeJS):
(function() {
// Wrong
setTimeout(function() {
var i;
for (i = 0; i < 5; ++i) {
setTimeout(function() {
show("wrong", i);
}, i * 50);
}
}, 0);
// Right
setTimeout(function() {
var i;
for (i = 0; i < 5; ++i) {
setTimeout(makeHandler(i), i * 50);
}
function makeHandler(index) {
return function() {
show("right", index);
};
}
}, 500);
function show(marker, val) {
display("show (" + marker + "): " + val);
}
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
})();
Live copy | source
Here's the output:
show (wrong): 5 show (wrong): 5 show (wrong): 5 show (wrong): 5 show (wrong): 5 show (right): 0 show (right): 1 show (right): 2 show (right): 3 show (right): 4
This is the correct usage of setTimeout
setTimeout(balm, time, i);
You have to pass a function, then delay, and then args to the aforementioned function