在forEach之后发送响应

时间:2016-01-11 11:18:46

标签: node.js foreach fs

(请注意,这不是两个类似标题的重复,这两个问题使用Mongoose,答案仅适用于Mongoose查询)

我有一个目录列表,每个目录都包含一个文件。我想返回一个JSON列表,其中包含每个文件的内容。我可以加载文件没问题,但因为我用forEach循环遍历数组,我的空响应是在我实际加载文件内容之前发送的:

function getInputDirectories() {
    return fs.readdirSync(src_path).filter(function(file) {
        return fs.statSync(path.join(src_path, file)).isDirectory();
    });
}

router.get('/list', function(req, res, next) {
    var modules = [];
    var input_dirs = getInputDirectories();

    input_dirs.forEach(function(dir) {
        path = __dirname+'/../../modules/input/'+dir+'/module.json'
        fs.readFile(path, 'utf8', function(err, data) {
            modules.push(data);
        });
    });

    res.status(200).json(modules);
});

如何确保我只在满载后发送modules数组,即:forEach完成后。

3 个答案:

答案 0 :(得分:1)

由于fs.readFile是异步的,因此您所拥有的行为很可能是预期的行为。

您需要做的是在读取所有模块后返回模块。你可以在fs.readFile内完成。

据我所知,您可以通过input_dirs.length获取目录总数(因为我猜getInputDirectories()正在返回一个数组)。现在你需要某种计数器来帮助你理解你是否已经阅读了最后一个目录,如果是,那么你将返回你的模块。这样的事情应该有效:

router.get('/list', function(req, res, next) {
    var modules = [];
    var input_dirs = getInputDirectories();
    var c = 0;

    input_dirs.forEach(function(dir) {

        path = __dirname+'/../../modules/input/' + dir + '/module.json'

        fs.readFile(path, 'utf8', function(err, data) {
            c++;

            modules.push(data);

            if(c == input_dirs.length) {
                return res.status(200).json(modules);
            }
        });
    });

});

答案 1 :(得分:1)

我建议您使用Promises,例如:

var Promise = require('bluebird');

router.get('/list', function(req, res, next) {
    var modules = [];
    var input_dirs = getInputDirectories();

    // 'each' will try to fulfill all promises, if one fails, it returns a
    // failed promise.
    return Promise.each(input_dirs, function(dir){
        path = __dirname+'/../../modules/input/'+dir+'/module.json';
        return new Promise(function(resolve, reject){
            fs.readFile(path, 'utf8', function(err, data) {
                if (err) return reject(err);
                return resolve(data);
            });
        });
    }).then(function(modules){
        return res.status(200).json(modules);
    })
    .catch(function(err){
        if (err) {
            //handle error
        }
    });

});

这样,一旦你履行了承诺,就会移动一个。

答案 2 :(得分:0)

而不是fs.readFile使用fs.readFileSync