在 forEach 之后发送响应

Sending response after forEach

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

我有一个目录列表,每个目录都包含一个文件。我想要 return 一个包含每个文件内容的 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 完成。

由于 fs.readFile 是异步的,您的行为很可能是预期的行为。

你需要做的是return你的模块,当所有的模块都被读取后。您可以在 fs.readFile 内执行此操作。

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

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);
            }
        });
    });

});

而不是 fs.readFile 使用 fs.readFileSync

我建议你使用 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
        }
    });

});

这样一来,您就可以在兑现承诺后移动一个。