在 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
}
});
});
这样一来,您就可以在兑现承诺后移动一个。
(请注意,这不是两个标题相似的问题的重复,这两个问题使用 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
}
});
});
这样一来,您就可以在兑现承诺后移动一个。