我正在使用Node / Mongoose / Express应用程序,我在使用forEach时遇到更新数组时遇到问题。我不是百分百肯定我错过了什么。这与同步与异步有关吗?我也可能只是错了。
router.route('/:slug/episodes')
.get(function(req, res) {
var episodeArray = [];
var episodeDetails = null;
Show.findOne({ 'slug': req.params.slug }, function(err, show) {
if (err) {
res.send(err);
}
var episodes = show.episodes
episodes.forEach(function(episodeID, index) {
Episode.findById(episodeID, function(err, episode) {
if (err) {
res.send(err);
}
episodeArray.push(episode);
});
});
res.send(episodeArray)
});
});
episodeArray没有添加剧集,最终只是充满了空值。
答案 0 :(得分:0)
在将数组发送回客户端之前,您不是在等待异步操作完成。
尝试这样的事情:
var togo = episodes.length;
var error;
episodes.forEach(function(episodeID, index) {
Episode.findById(episodeID, function(err, episode) {
if (err) {
if (!error)
error = err;
} else
episodeArray.push(episode);
if (--togo === 0)
res.send(error ? error : episodeArray);
});
});
此外,如果在异步操作期间遇到错误,您应该添加return;
,以防止执行其余代码。
答案 1 :(得分:0)
您的代码误解了异步的工作方式。首先,你应该阅读@elclanrs发布的Felix Kling链接 here。 SO贡献者往往厌倦了一遍又一遍地回答相同的异步问题。我还没有那么累,所以我会为了解释异步而咬人,但我还会建议另一种选择,这可能是解决问题的更好方法。
异步解决方案:有许多方法可以等待异步操作数组完成。 async.queue
是一个受欢迎的选择。工作原理是将一组待处理操作推送到队列中,然后告诉该队列等待直到收到所有结果,此时执行res.send()。代码看起来像这样:
var async = require('async');
Show.findOne({
'slug': req.params.slug
}, function(err, show) {
if (err) {
res.send(err);
}
var episodeArray = [];
var queue = async.queue(function(episodeID, callback) {
Episode.findById(episodeID, function(err, episode) {
if (err) {
throw err;
}
episodeArray.push(episode);
callback();
});
});
// Note that forEach is synchronous.
// The tasks will be pushed to the queue before drain()
episodes.forEach(function(episodeID, index) {
queue.push(episodeId);
});
queue.drain = function() {
res.send(episodeArray);
};
});
这不是解决问题的最佳方式,这只是为了演示如何修复现有代码。
只要您的剧集阵列不是非常庞大,那么查询剧集的更好方法可能是使用mongoDB的$in
运算符,如下所示:
Show.findOne({
'slug': req.params.slug
}, function(err, show) {
if (err) {
res.send(err);
}
Episode.find({
_id: {
$in: show.episodes
}
}, function(err, episodes) {
if (err) {
throw err;
}
res.send(episodes);
});
});
修改强>
如果你想深入一点,我还应该提一下,mongoose支持promises,你可以使用它来使你的代码更少嵌套和重复,如下所示:
Show.findOne({
slug: req.params.slug
})
.then(function(show) {
return Episode.find({
_id: {
$in: show.episodes
}
});
})
.then(function(episodes) {
res.send(episodes);
})
// Any errors returned above will short circuit to the middleware next() here
.error(next);