为什么NodeJS shell和编译器对变量的赋值不一致?

时间:2015-07-06 15:10:21

标签: javascript node.js mongodb

以下是文件tags.js的内容。

//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并将相同的代码复制粘贴到shell中)时,console.log(ln)打印[] }和console.log(lm)打印我想从MongoDB中检索的文档的内容。

有人可以解释这种行为吗?

2 个答案:

答案 0 :(得分:1)

正如一些评论者指出的那样,问题是findElemHelper方法的异步性质。其中一条评论中发布的long, but detailed answer解释了javascript中异步的基础知识以及如何处理这种编码风格。

简而言之,对于异步代码,您不能假设操作顺序与代码中的语句相同。您在确定问题难题的位置时是正确的,但问题不在于范围,而是在数据库返回数据时调用传递给tempCurs.toArray的函数,这可能是在其余的数据之后。文件已完成执行。 (传递到MongoClient.connect的函数也是如此,在db甚至连接之前你最终可能会调用console.log!)

以下是我们如何使用回调来解决问题,目标是构建我们的代码,以确保数据库在调用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);

});

答案 1 :(得分:0)

你的函数findElemHelper使用回调对MongoDB进行异步调用。因此,您不知道arrayToReturn何时填充其内容。机会是,在控制台中打印lm意味着你给了它足够的时间来实际填充。

您应该尝试重构代码,以便可以在回调中使用异步调用的响应,而不是在全局变量外部。