2012-03-20 2 views
1

В моем приложении у меня есть следующий:Node.js/socket.io исчезает переменную

client.on('test', function(req, fn) { 
     var returnArr = []; 
     redis.hkeys(req, function (err, replies) { 
      replies.forEach(function(reply, i) { 
       if (reply.indexOf('list.') > -1) { 
        redis.hgetall(reply.substring(5), function(err, r) { 
         returnArr.push({name:r['name'],index:i}); 
         console.log(returnArr); 
        }); 
       } 
      }); 
      console.log(returnArr); 
     }); 
     console.log(returnArr); 
    }); 

По какой-то причине, вторые и третьи журналы содержат пустой массив, даже если массив объявлен один раз в beginnning события. Есть идеи?

EDIT: Извините, я изменил имя переменной, когда разместил ее здесь, не задумываясь. Это происходит, когда он называется что угодно.

+2

Не вызывайте переменную 'return'. –

+0

Я изменил исходный вопрос, когда вы отправляете вопрос, я изменил имя переменной, не задумываясь. Это происходит независимо от его имени. – grsx

ответ

3

Эти Redis вызовы являются асинхронными. Вот почему вы предоставляете им обратные вызовы. Код не будет работать, даже если вы исправите имя переменной по этой причине.

Чтобы уточнить: код, полученный при обратном вызове на «hkeys», будет вызываться, когда данные будут доступны. Однако вызов будет немедленно возвращен, поэтому ваш массив не будет иметь ничего в этом месте.

Вы не можете обернуть асинхронные вызовы в функции и ожидать возврата значения. Это просто не сработает.

Вместо этого общий шаблон должен делать то же, что и API-интерфейс redis (и практически все остальное в мире node.js; это как бы то самое на самом деле): дать вашей собственной функции вызываемый аргумент обратного вызова когда это необходимо. В вашем случае это будет внутри обратного вызова «hgetall», который является последним для вызова. Он должен понять, что ваш массив результатов имеет столько же значений, сколько есть ключей, и поэтому пришло время вызвать обратный вызов, переданный вашей функции.

(я должен отметить, что не ясно, что вы пытаетесь сделать, учитывая, что функция в целом, как представляется, обратный вызов к чему-то.)

Другой подход будет использовать какой-то «обещание» хотя это действительно просто перестройка той же идеи.

редактировать — общий шаблон для API с обратного вызова будет что-то вроде этого:

function yourAPI(param1, param2, callback) { 
    // ... 
    some.asynchronousFunction(whatever, function(result) { 
    callback(result); 
    } 
} 

Теперь в вашем случае вы делаете несколько асинхронных запросов на обслуживание, и вы должны были бы чтобы выяснить, когда пришло время вызвать обратный вызов. Я думаю, что вы, вероятно, хотите, чтобы перебирать «ответов» от звонка, чтобы получить ключи и извлечь список тех, которые вы хотите получать:

redis.hkeys(req, function (err, replies) { 
     var keys = []; 
     replies.forEach(function(reply, i) { 
      if (reply.indexOf('list.') > -1) { 
       keys.push(reply.substring(5)); 
      } 
     }); 
     keys.forEach(function(key) { 
       redis.hgetall(key, function(err, r) { 
        returnArr.push({name:r['name'],index:i}); 

        if (returnArr.length === keys.length) { 
         // all values ready 
         callback(returnArr); 
        } 
       }); 

     }); 
+0

Как вы рекомендуете делать это? – grsx

+0

@grsx Я обновил ответ. Я не совсем уверен, что вы пытаетесь сделать; другими словами, ваш вопрос явно является результатом вашего тестирования, чтобы определить, что происходит, но неясно, что вы в конечном итоге будете делать с «returnArr». – Pointy

+0

В принципе, мне нужно вернуть список элементов, запрашиваемых клиентом из магазина redis. Как только это будет сделано, мне нужно вернуть все результаты как объекты внутри массива. Этот массив затем передается клиенту для выполнения любых задач. – grsx

1

Вы не можете назвать свою переменную return

Это один из немногих зарезервированных слов, которые вы не можете использовать в своем коде, как переменные.

1

@Pointy ответил на этот вопрос односложно уже, но позвольте мне объяснить, это немного более ясно: те вложенные функции не запускаются в том порядке, в котором вы думаете.

Node.js является неблокирующим и использует неявный цикл событий Javascript для их выполнения при их готовности.Вот ваш код с номерами строк:

/*01*/ client.on('test', function(req, fn) { 
/*02*/  var returnArr = []; 
/*03*/  redis.hkeys(req, function (err, replies) { 
/*04*/   replies.forEach(function(reply, i) { 
/*05*/    if (reply.indexOf('list.') > -1) { 
/*06*/     redis.hgetall(reply.substring(5), function(err, r) { 
/*07*/      returnArr.push({name:r['name'],index:i}); 
/*08*/      console.log(returnArr); 
/*09*/     }); 
/*10*/    } 
/*11*/   }); 
/*12*/   console.log(returnArr); 
/*13*/  }); 
/*14*/  console.log(returnArr); 
/*15*/ }); 
/*16*/ //Any other code you have after this. 

Итак, каков порядок выполнения этой вещи?

Строка 1: зарегистрируйте обработчик событий для события 'test'.

Линия 16: Начало работы любой другой код, который будет работать во время этого прохода через цикл событий

Line 2: A «тест» событие было получено в какой-то момент по циклу событий и в настоящее время обрабатывается, поэтому инициализируется returnArr

Строка 3: Выполняется неблокирующий запрос ввода-вывода, и функция обратного вызова регистрируется для выполнения, когда соответствующее событие помещается в очередь в цикле событий.

Строка 14-15: Выполняется console.log Выполняется эта функция, которая должна заканчивать текущее обрабатываемое событие.

Строка 4: Событие запроса возвращается и выполняется обратный вызов. Метод forEach является одним из немногих , блокирующих методы Node.js с обратным вызовом, поэтому каждый обратный вызов выполняется для каждого ответа.

Строка 5: if оператор выполняются и либо заканчивается (переходят в линии 10) или поступают в блоке (идет к строке 6)

Строка 6: Запрос неблокирующего ввода-вывода выполняются, при добавлении нового событие в цикл событий и новый обратный вызов, который будет запущен, когда событие вернется.

Строка 9: Завершение регистрации обратного вызова.

Линия 10: Завершает if заявление

Строка 11: Завершает `forEach обратных вызовов.

Линия 12: Выполнение второгоconsole.log запрос , который до сих пор не имеет ничего в returnArr

Линия 7: Одна из возвращений событий и пожаров обработчик событий. Новым данным присваивается returnArr.

Строка 8: перваяconsole.log выполнено. В зависимости от того, какое событие это, длина массива будет отличаться. Также порядок элементов массива НЕ должен соответствовать порядку ответов, перечисленных в массиве replies.

По существу, вы можете посмотреть на более глубоко вложенные функциях, выполнение после полноты менее, глубоко вложенных функций (потому что это то, что происходит, по сути), независимо от того, содержит ли метод заявление после вложенной неблокируемой обратный вызов или нет.

Если это смущает вас, вы можете написать код обратного вызова в Continuation Passing Style так что очевидно, что все во внешней функции выполняются до внутренней функции, или вы можете использовать this nice async library, чтобы сделать ваш код выглядеть более важен.

Это, я думаю, отвечает на ваш реальный вопрос, а не на тот, который вы ввели.

+0

Спасибо за подробное объяснение. Это очень ценится. Он отвечает, почему переменная была пуста, но я отметил, что Pointy's является ответом, поскольку он содержит разрешение. Я бы назвал оба, если мог, или проголосовать за вас, но мне нужно 15 представителей, чтобы проголосовать за него. – grsx

Смежные вопросы