I'm an experienced software developer, but pretty new to JS and to node. I'm not a big fan of super-nested code, so I've been trying to break callbacks out into their own functions. I'm having trouble though with figuring out how to maintain scope when the callback fires. Digging around I read that if I created a closure over the callback it would work, but it doesn't seem to work the way I expected it would.
Here's a very simple version of the kind of code that isn't working for me:
function writeBody()
{
res.end("<h1> Hooray! </h1>");
}
http.createServer(function(req, res)
{
res.writeHead('Content-Type', 'text/html');
setTimeout(function(){writeBody()}, 2000);
}).listen(8000);
I thought that by wrapping the writeBody() call in the function() closure I would have the scope I needed after the timeout, but when writeBody() fires I get
ReferenceError: res is not defined
Can anyone tell me what boneheaded thing I am doing wrong?
Basically that not how closures work, functions inherit their outer scopes that's how it works.
// this function only inherits the global scope
function writeBody()
{
res.end("<h1> Hooray! </h1>");
}
http.createServer(function(req, res) // a new local varaible res is created here for each callback
{
res.writeHead('Content-Type', 'text/html');
// annonymous function inheris both the global scope
// as well as the scope of the server callback
setTimeout(function(){
// the local variable res is available here too
writeBody()
}, 2000);
}).listen(8000);
To make it work just pass the res
object into the function, as it's available in the timeout callback.
function writeBody(res)
{
// NOT the same variable res, but it holds the same value
res.end("<h1> Hooray! </h1>");
}
http.createServer(function(req, res)
{
res.writeHead('Content-Type', 'text/html');
setTimeout(function(){
writeBody(res); // just pass res
}, 2000);
}).listen(8000);
But you need to watch out for things like this:
for(var i = 0; i < 10; i++) { // only one i gets created here!()
setTimeout(function() {
console.log(i); // this always references the same variable i
}, 1000);
}
This will print 10
ten times, because the reference is the same and i
gets incremented all the way up to 10
. If you want to have the different numbers you need to create a new variable for each one, either by wrapping the setTimeout
into an anonymous self function which you pass in the i
as a parameter, or by calling some other method which sets up the timouet and receives the i
as a parameter.
// anoynmous function version
for(var i = 0; i < 10; i++) {
(function(e){ // creates a new variable e for each call
setTimeout(function() {
console.log(e);
}, 1000);
})(i); // pass in the value of i
}
// function call version
for(var i = 0; i < 10; i++) {
createTimeoutFunction(i);
}
You can also make the functions nested, so they share scope, ie
http.createServer(function(req, res)
{
function writeBody()
{
res.end("<h1> Hooray! </h1>");
}
res.writeHead('Content-Type', 'text/html');
setTimeout(function(){writeBody()}, 2000);
}).listen(8000);
I often find this is easier than always passing a bunch of variables in to keep in scope, although it means you cannot reuse the function elsewhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With