Javascript module.exports节点中的问题

Javascript module.exports节点中的问题,javascript,node.js,csv,module,Javascript,Node.js,Csv,Module,我正在练习node.js,我有一些疑问 我有一个csv文件users.csv,并且我创建了一个节点模块library.js来返回csv文件中的值。当我从我的程序中调用模块时,我得到了非常好的结果。我的程序如下 users.csv id,name 1,Jim 2,Jo library.js var csv = require("fast-csv"); var DataToBeReturned = []; exports.users = function () {

我正在练习node.js,我有一些疑问

我有一个csv文件users.csv,并且我创建了一个节点模块library.js来返回csv文件中的值。当我从我的程序中调用模块时,我得到了非常好的结果。我的程序如下

users.csv

id,name
1,Jim
2,Jo
library.js

var csv             = require("fast-csv");
var DataToBeReturned = [];
exports.users = function () {
        csv.fromPath("users.csv", {headers: true})
        .on("data",function(data){
            DataToBeReturned.push(data);
        })
        .on("end",function(){   
            console.log(DataToBeReturned.length);
            return DataToBeReturned;
        });
};
app.js

var mylibrary = require('./library.js');
console.log(mylibrary.users());
console.log(mylibrary.users());
我的预期产出是

2
[{ id: '1', name: 'Jim' },{ id: '2', name: 'Jo' }]
2
[{ id: '1', name: 'Jim' },{ id: '2', name: 'Jo' }]
相反,我得到了

undefined
undefined
3
4
我的疑问是:

为什么返回值未定义? 为什么我的计数不总是2?
提前感谢。

我自己还不能测试您的代码,但是从阅读您的代码中,您遇到了两个问题,这两个问题与您的问题密切相关

首先,您遇到了大多数人在开始使用nodejs时遇到的典型问题。您正在同步调用一个异步函数。这就是为什么它会打印未定义的前两次,即打印调用用户的结果。由于用户尚未完成运行,因此其值未定义。您应该使用回调函数实现library.js函数users。例如:

exports.users = function (callback) {
    csv.fromPath("users.csv", {headers: true})
    .on("data",function(data){
        DataToBeReturned.push(data);
    })
    .on("end",function(){   
        console.log(DataToBeReturned.length);
        return callback(null, DataToBeReturned);
    });
};
然后在app.js中,您将实现此功能以处理回调

var csv             = require("fast-csv");
// err is just a nodejs convention, if you add error checking to users,
// instead of throwing an error, you would pass it back as the first agrument
// to the callback
mylibrary.users(function(err, users) {
    console.log(users);
});
mylibrary.users(function(err, users) {
    console.log(users);
});
其次,您引用的是用户函数中的全局变量。那就是你打印出的3和4。两个调用同时作用于变量。当第一个调用完成并返回值时,第二个调用已经修改了数组。因此,您希望移动数组声明而不是函数,这样只有其中的代码才能访问它

exports.users = function () {
    var DataToBeReturned = [];
    // the rest of your code.
};
编辑:模块内部的代码被缓存,因此只执行一次。然后引用它的每个脚本都会简单地返回该副本。如果您只需要读取csv一次,请利用此功能

var DataToBeReturned = [];
var called = false;
function read(callback) {
    if (called) {
        process.nextTick(function() {
            return callback(null, DataToBeReturned);
        });
        return;
    } else {
        called = true;
        csv.fromPath("users.csv", {headers: true})
        .on("data",function(data){
            DataToBeReturned.push(data);
        })
        .on("end",function(){   
            console.log(DataToBeReturned.length);
            return callback(null, DataToBeReturned);
        });
    }
};

exports.users = function(callback) {
    return read(callback);
};

process.nextTick部分很重要,有关它如何工作的更多信息可以在文档中找到。

可能与@BenFortune重复,这是一个好发现,Felix对该问题的回答涉及到了异步编程的更多细节。谢谢@Zequ。有了这个解决方案,我得到了正确的答案。但我又面临另一个问题。每次调用该方法时,它都在读取文件。相反,我只需要读取文件一次