Как сохранить объем в node.js обратных вызовах?
Я опытный разработчик программного обеспечения, но довольно новичок в JS и node. Я не большой поклонник супер-вложенного кода, поэтому я пытаюсь разбить callbacks на свои собственные функции. У меня возникли проблемы, хотя вы выяснили, как поддерживать область действия, когда срабатывает обратный вызов. Копая вокруг, я читал, что если бы я создал закрытие над обратным вызовом, это сработало бы, но, похоже, оно не работает так, как я ожидал.
Здесь очень простая версия кода, который не работает для меня:
function writeBody()
{
res.end("<h1> Hooray! </h1>");
}
http.createServer(function(req, res)
{
res.writeHead('Content-Type', 'text/html');
setTimeout(function(){writeBody()}, 2000);
}).listen(8000);
Я думал, что, завернув вызов writeBody() в закрытии функции(), я бы получил область, которая мне нужна после таймаута, но когда fireBody() срабатывает, я получаю
ReferenceError: res не определен
Может ли кто-нибудь сказать мне, что за то, что я делаю неправильно?
Ответы
Ответ 1
В принципе, не так, как работают замыкания, функции наследуют свои внешние области, как это работает.
// 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);
Чтобы заставить его работать, просто передайте объект 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);
Но вам нужно следить за такими вещами:
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);
}
Это будет печатать 10
десять раз, потому что ссылка одинаковка, а i
получает приращение вплоть до 10
. Если вы хотите иметь разные числа, необходимые для создания новой переменной для каждого из них, либо обернув setTimeout
в анонимную self-функцию, которую вы передаете в i
в качестве параметра, либо вызываете какой-либо другой метод, который устанавливает 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);
}
Ответ 2
Вы также можете сделать функции вложенными, поэтому они обмениваются областью, то есть
http.createServer(function(req, res)
{
function writeBody()
{
res.end("<h1> Hooray! </h1>");
}
res.writeHead('Content-Type', 'text/html');
setTimeout(function(){writeBody()}, 2000);
}).listen(8000);
Я часто нахожу, что это проще, чем всегда передавать кучу переменных для хранения в области видимости, хотя это означает, что вы не можете повторно использовать эту функцию в другом месте.
Ответ 3
Вы можете передать ответ в своем обратном вызове так:
http.createServer(function(req, res)
{
res.writeHead('Content-Type', 'text/html');
setTimeout(function(){writeBody(res)}, 2000);
}).listen(8000);
Ответ 4
Мне действительно нравится ответ Джастина Кормака. Вот более яркий пример недавнего кодирования моего.
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();
};
Большинство людей скажут мне (и они это делают), что это правильный способ написать этот код.
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();
})});
};
Возможно, я n00b, но я считаю, что вложенные обратные вызовы немного усердны. Я также допускаю, что группа функций f0, f1, f2 является хромой. В любом случае, это хороший пример области.