@ Пойнти уже ответил на это кратко, но позвольте мне объяснить это более четко: эти вложенные функции выполняются не в том порядке, в каком вы думаете.
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: начать выполнение любого другого кода, который будет выполняться во время этого прохода через цикл обработки событий
Строка 2. Событие 'test' было получено в определенный момент циклом событий и теперь обрабатывается, поэтому returnArr
инициализируется
Строка 3: выполняется неблокирующий запрос ввода-вывода, и регистрируется функция обратного вызова для выполнения, когда соответствующее событие ставится в очередь в цикле событий.
Строка 14-15: last console.log
выполняется, и эта функция завершается, что должно завершить текущее обрабатываемое событие.
Строка 4: событие запроса возвращается и выполняется обратный вызов. Метод forEach
является одним из немногих , блокирующих методы Node.js с обратным вызовом, поэтому каждый обратный вызов выполняется при каждом ответе.
Строка 5: оператор if
выполняется и либо заканчивается (переходит к строке 10), либо входит в блок (переходит к строке 6)
Строка 6: выполняется неблокирующий запрос ввода-вывода, добавление нового события в цикл событий и новый обратный вызов для запуска при возвращении события.
Строка 9: Завершает регистрацию обратного вызова.
Строка 10: завершает оператор if
Строка 11: завершение обратных вызовов `forEach
.
Строка 12: выполняет второй console.log
запрос, который по-прежнему не имеет ничего в returnArr
Строка 7: одно из событий возвращает и запускает обработчик события. returnArr
дается новые данные.
Строка 8: first console.log
выполняется. В зависимости от того, какое это событие, длина массива будет разной. Также порядок элементов массива НЕ должен соответствовать порядку ответов, перечисленных в массиве replies
.
По сути, вы можете рассматривать более глубоко вложенные функции как выполняющие после всей совокупности менее глубоко вложенных функций (потому что именно это и происходит), независимо от того, содержит ли метод операторы после вложенных неблокирующий обратный вызов или нет.
Если вас это смущает, вы можете написать свой код обратного вызова в Стиль передачи продолжения , так что очевидно, что все во внешней функции выполняется перед внутренней функцией, или вы можете использовать эта прекрасная асинхронная библиотека , чтобы сделать ваш код более обязательным.
Это, я думаю, отвечает на ваш реальный вопрос, а не на тот, который вы ввели.