forEach over array with .push into another array
forEach over array with .push into another array
我正在开发 Node / Mongoose / Express 应用程序,但在使用 forEach 时遇到要更新数组的问题。我不是 100% 确定我错过了什么。这与同步与异步有关吗?我也可能只是 return 错了。
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 没有添加剧集,最终只是充满了空值。
在将数组发送回客户端之前,您没有等待异步操作完成。
尝试这样的事情:
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;
,以防止执行其余代码。
您的代码对异步的工作方式存在误解。首先,您应该阅读@elclanrs 发布的 Felix Kling link 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);
我正在开发 Node / Mongoose / Express 应用程序,但在使用 forEach 时遇到要更新数组的问题。我不是 100% 确定我错过了什么。这与同步与异步有关吗?我也可能只是 return 错了。
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 没有添加剧集,最终只是充满了空值。
在将数组发送回客户端之前,您没有等待异步操作完成。
尝试这样的事情:
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;
,以防止执行其余代码。
您的代码对异步的工作方式存在误解。首先,您应该阅读@elclanrs 发布的 Felix Kling link 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);