2015-07-06 2 views
0

Ниже приведено содержимое файла tags.js.Почему оболочка и компилятор NodeJS не согласны с назначением переменных?

//the following initializes the MongoDB library for Javascript. 
var MongoClient = require('mongodb').MongoClient, 
assert = require('assert'); 

//connection URL 
abc = 'mongodb://localhost:27017/abcbase/ 

/* the following is a global variable 
    where I want retrieved content */ 
var arrayToReturn = []; 

/* toFind is a dictionary, toSearch is a 
    MongoDB collection (input is its name as a string) */ 
function findElemHelper(toSearch, toFind) { 
    /* establishes connection to the database abcbase 
     and runs the contents of the function that is 
     the second input */ 
    MongoClient.connect(abc, function(err, db) { 
     /* coll is the collection being searched. 
      tempCurs is the results of the search returned 
      as a cursor 
     */ 
     coll = db.collection(toSearch); 
     tempCurs = coll.find(toFind); 
     /* the three lines below this comment 
      form the crux of my problem. I expect 
      arrayToReturn to be assigned to docs 
      (the contents of the cursor received by 
      the find function). Instead it seems like 
      it is declaring a new variable in local scope.*/ 
     tempCurs.toArray(function(err, docs) { 
      arrayToReturn = docs; 
     }); 
    }); 
} 

function findElem(toSearch, toFind) { 
    findElemHelper(toSearch, toFind); 
    return arrayToReturn; 
} 

function returnF() { 
    return arrayToReturn; 
} 

var ln = findElem("userCollection", {}); 
var lm = returnF(); 

console.log(ln); 
console.log(lm); 

При запуске файла с помощью интерпретатора узла с помощью команды node tags.js, он печатает

[] 
[] 

И когда я запускаю тот же самый код интерпретатора узла (который я вхожу с командой node из Терминал и скопировать-вставить тот же код в оболочку), console.log(ln) отпечатки [] и console.log(lm) распечатывает содержимое документа, который я хочу извлечь из MongoDB.

Не могли бы вы объяснить это поведение?

+0

Возможно, вы используете 'returnF', прежде чем' findElem' будет завершен. Многие действия в node.js являются асинхронными, например, связь с базой данных. –

+0

Возможный дубликат [Как вернуть ответ от асинхронного вызова?] (Http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) –

+0

Don ' Знаю. Возможно, REPL просто занимает больше времени, поэтому ответ может вернуться. Не имеет значения, так как это не значит, что ваш код будет работать. –

ответ

0

Ваша функция findElemHelper выполняет асинхронный вызов MongoDB с обратным вызовом. Таким образом, вы действительно не знаете, когда заполнено содержимое массива. Скорее всего, печать lm в консоли означает, что вы дали ему достаточно времени для фактического заполнения.

Вы должны попытаться перестроить свой код, чтобы вы могли использовать ответ от асинхронного вызова в своем обратном вызове, а не снаружи в глобальной переменной.

1

Как отмечают некоторые комментаторы, проблема заключается в асинхронном характере метода findElemHelper. В этом long, but detailed answer, опубликованном на одном из комментариев, объясняются основы асинхронизации в javascript и способы подхода к этому стилю кодирования в целом.

В более коротком ответе, с асинхронным кодом, вы не можете считать, что порядок операций аналогичен операциям в вашем коде. Вы правильно определяете местоположение проблемы вашей проблемы, но проблема не в области, а в том, что функция, которую вы передали в tempCurs.toArray, вызывается всякий раз, когда база данных возвращает данные, которые могут быть после завершения оставшейся части файла , (То же самое относится к функции, переданной в MongoClient.connect, где вы могли бы позвонить console.log, прежде чем db даже подключится!)

Вот как мы решаем проблему с обратными вызовами, цель состоит в том, чтобы структурировать наш код таким образом, чтобы мы были убедитесь, что база данных вернула данные перед вызовом console.log:

var MongoClient = require('mongodb').MongoClient; 

var abc = 'mongodb://localhost:27017/abcbase/'; 

/** 
* Take a callback function as the last parameter which will 
* be called when the array is retrieved. 
*/ 
function findElem(toSearch, toFind, callback) { 

    MongoClient.connect(abc, function(err, db) { 

    var coll = db.collection(toSearch); 
    var tempCurs = coll.find(toFind); 
    tempCurs.toArray(callback); 

    }); 
} 

findElem("userCollection", {}, function(err, docs) { 

    console.log(docs); 

});