javascript 如何在 node.js 回调中维护范围?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4357881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I maintain scope in node.js callbacks?
提问by MahatmaManic
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.
我是一名经验丰富的软件开发人员,但对 JS 和 node 还是很陌生。我不是超级嵌套代码的忠实粉丝,所以我一直试图将回调分解为它们自己的函数。我在弄清楚回调触发时如何维护范围时遇到了麻烦。挖掘周围我读到,如果我在回调上创建了一个闭包,它会起作用,但它似乎不像我预期的那样起作用。
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
我认为通过将 writeBody() 调用包装在 function() 闭包中,我将拥有超时后所需的范围,但是当 writeBody() 触发时,我得到
ReferenceError: res is not defined
参考错误:未定义 res
Can anyone tell me what boneheaded thing I am doing wrong?
谁能告诉我我做错了什么愚蠢的事情?
回答by Ivo Wetzel
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 resobject into the function, as it's available in the timeout callback.
要使其工作,只需将res对象传递给函数,因为它在超时回调中可用。
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 10ten times, because the reference is the same and igets 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 setTimeoutinto an anonymous self function which you pass in the ias a parameter, or by calling some other method which sets up the timouet and receives the ias a parameter.
这将打印10十次,因为引用是相同的并且i一直递增到10。如果您想拥有不同的数字,您需要为每个数字创建一个新变量,方法是将 包装setTimeout到您i作为参数传入的匿名 self 函数中,或者通过调用其他一些方法来设置 timouet 并接收在i作为参数。
// 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);
}
回答by Justin Cormack
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.
我经常发现这比总是传递一堆变量以保持在范围内更容易,尽管这意味着您不能在其他地方重用该函数。
回答by fijiaaron
You can pass response in your callback so:
您可以在回调中传递响应,以便:
http.createServer(function(req, res)
{
res.writeHead('Content-Type', 'text/html');
setTimeout(function(){writeBody(res)}, 2000);
}).listen(8000);
回答by rocketsarefast
I actually like Justin Cormack's answer. Here is a more extreme example of some recent coding of mine.
我实际上喜欢 Justin Cormack 的回答。这是我最近编码的一个更极端的例子。
var Func4 = function(req, res)
{
var collectionName = "parts";
var f0 = function() {mongodbClient.collection(collectionName, f1);};
var f1 = function(err, coll) {coll.ensureIndex("item", f2);};
var f2 = function(err, indexname)
{
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write("index name = " + indexname);
res.end();
};
f0();
};
Most people would tell me (and they do) that this is the correct way to write that code.
大多数人会告诉我(并且他们确实这样做了)这是编写该代码的正确方法。
var Func4 = function(req, res)
{
var collectionName = "parts";
mongodbClient.collection(collectionName, function(err, coll) {
coll.ensureIndex("item", function(err, indexname) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write("index name = " + indexname);
res.end();
})});
};
Perhaps I am a n00b, but I find nested callbacks a bit hard to follow. I also admit a bunch of f0,f1,f2 functions is lame. Either way, this is a good example of scope.
也许我是一个 n00b,但我发现嵌套回调有点难以理解。我也承认一堆 f0,f1,f2 函数是蹩脚的。无论哪种方式,这是范围的一个很好的例子。

