2014-01-24 9 views
2

По какой-то причине я не могу установить цикл collection.count. Он сохраняет печать filename[5] 5 раз, а не начинается с 1 и переходит к 5.Невозможно выполнить функции коллекции MongoDB

Это не имеет смысла, потому что я могу вручную копировать и вставлять эту функцию 5 раз, и она будет работать, но когда в цикле for это не работает, т.

for(var k =0; k<(filename.length)-2;k++) { 

    collection.count({ "display.Name": filename[k] } , function(err, count) { 
     console.log("Filename: " +filename[k]); 
     console.log(" Trips: " + count); 

    }); 

} 

ПРИМЕЧАНИЕ: Если я ставлю console.log за пределами collection.count, я буду видеть все 5 из моих имен файлов. Только в пределах конкретной функции это не работает.

ответ

4

Позвольте мне попытаться объяснить это, не извергая слова суп и выкидывая массу веселых терминов, таких как «асинхронный», «цепочка областей действия» или «закрытие».

Проблема возникает из-за того, что ваша петля заканчивается задолго до того, как возвращается первый запрос MongoDB. К моменту, когда ваш обратный вызов работает, переменная k прошла через цикл 5 раз и теперь равна 5. Таким образом, к моменту, когда все пять ваших обратных вызовов вернутся, console.log("Filename: " + filename[k]); будет console.log("Filename: " + filename[5]); каждый раз.

Правильные запросы выполняются, потому что новый запрос начинается на каждой итерации цикла и использует k, пока он находится в правильном значении; однако, переменная k определяется в рамках выше ваш обратный вызов так, когда обратные вызовы, наконец, огонь, k долго будет закончен с инкрементируется до 5.

Попробуйте вместо этого:

for(var k =0; k<(filename.length)-2;k++) { 
    (function (k) { 
     collection.count({ "display.Name": filename[k] } , function(err, count) { 
      console.log("Filename: " +filename[k]); 
      console.log(" Trips: " + count); 
     }); 
    })(k); 
} 

Теперь будет работать, потому что мы создали новую область вокруг переменной k. Все это означает, что у непрофессионалов есть то, что у вас есть две переменные с именем k. Первый - это тот, который вы определяете в цикле for, а второй - тот, который создается, когда самозапускающаяся функция вызывает себя, передавая в k. Аргумент функции также называется k, но это технически новое определение переменной. Это означает, что вторая переменная k будет NOT изменить на каждой итерации цикла, меняется только внешняя область.

На каждой итерации определена новая анонимная функция, и в нее передается k. Теперь, когда срабатывает обратный вызов, каждая из их k переменных будет уникальной и не будет такой же, как внешняя переменная k.

Чтобы упростить понимание, просто измените имя переменной в анонимной функции, так что это не то же самое, что и внешнее, и тогда вы поймете, почему это работает.

for(var k =0; k<(filename.length)-2;k++) { 
    (function (x) { 
     collection.count({ "display.Name": filename[x] } , function(err, count) { 
      console.log("Filename: " +filename[x]); 
      console.log(" Trips: " + count); 
     }); 
    })(k); 
} 

Другой необычный способ сделать то же самое, чтобы только обернуть функцию обратного вызова в новой области вместо всего запроса. Хотя я оставлю это до вас, чтобы решить, если это действительно легче читать или нет: P

for(var k =0; k<(filename.length)-2;k++) { 
    collection.count({ "display.Name": filename[k] } , (function (x) { 
     return function(err, count) { 
      console.log("Filename: " +filename[x]); 
      console.log(" Trips: " + count); 
     }; 
    })(k)); 
} 

В этом самоосуществляющейся функции поставляются в качестве второго аргумента collection.count. Функция самозапуска передается k, которая становится функцией x внутри функции самозапуска.Он немедленно возвращает другую функцию; функция, которая фактически будет передана как второй аргумент collection.count. Функция самозапуска становится видом мини-фабрики, которая возвращает другую функцию, которая теперь может ссылаться на переменную, определенную во внешней области (область внутри функции самозапускания), которая, как мы знаем, не изменится, поскольку технически существует новый анонимная функция (в комплекте с определением аргумента x) определяется на каждой итерации.

Иными словами, я уверен, что вы понимаете, что функция обратного вызова, которую вы определили, определяется пять раз; один раз для каждой итерации цикла. Хорошо то же самое касается анонимной функции самозапуска. Он также создается пять раз, включая аргумент, который теперь заблокирован, независимо от того, что значение k было в момент вызова функции.

Надеюсь, это имеет смысл. Это не сложная концепция, так как сложно объяснить это ясно.

+0

Отличное объяснение. Возможно, добавьте эту альтернативу. Вместо создания функции k или X просто выполните 'var vIndex = 0;' вместе с 'console.log (" Filename: "+ filename [vIndex]); \t \t \t \t vIndex ++; ' – krikara

+1

Да, я полагаю, кроме того, что добавочная лишняя переменная увеличивается и не работает, если требуемая переменная была чем-то более сложным, чем целочисленное число. Вы также не узнали бы ничего нового, если бы я просто исправил ваш код с помощью взлома. Научите человека ловить рыбу;) – Chev

+0

Да, я понимаю, что вы имеете в виду. Как только я начал делать больше, чем считать, индекс оказался ненадежным. – krikara

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