Подтвердить что ты не робот

Как сохранить объем в 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 не определен

Может ли кто-нибудь сказать мне, что за то, что я делаю неправильно?

4b9b3361

Ответ 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 является хромой. В любом случае, это хороший пример области.