在我的控制器(sails.js)中,我有一个数组,其中包含一个ID列表。
这些是来自另一个表的ID。我需要使用该ID提取每条记录,并将其发送给用户。
到目前为止,我已经制作了这段代码:
suggestions.forEach(function (element, index, array){
Suggester.findOne({
"id": element.suggester_id
},function(err,docs){
suggesterResults.push(docs);
console.log("I am adding to array: " + docs);
if (index === array.length - 1) {
completeSend(suggesterResults);
}
});
})
...
function completeSend (results) {
console.log("I am in complete send method" + results)
return res.send(results, 200);
}
这有效,但看起来像是作弊。在我看来这是阻止代码,这是不可接受的。在这种情况下是否有通常的做事方式?
答案 0 :(得分:3)
正确的方法是
Suggester.find({
id: suggestions.map(function(s) { return s.suggester_id; })
})
.then(completeSend);
您拨打find
一次,并传递一系列ID,一旦完成,completeSend
将被调用结果数组。
您提到所有这些已经成为承诺链的一部分,在这种情况下,.then()
有不良做法(不要嵌套.then()
来电!)
如果是这样,那么正确的方法是:
// Some promise chain logic here
.then(function(/* suggestions? */) {
return Suggester.find({
id: suggestions.map(function(s) { return s.suggester_id; })
});
})
.then(completeSend);
答案 1 :(得分:2)
承诺:
Promise.all(suggestions.map(function(suggestion) {
return Suggester.findOne({"id": suggestion.suggester_id});
})
.then(completeSend);
Promise.all(suggestions.map(function(suggestion) {
return Suggester.findOne({"id": suggestion.suggester_id});
})
将suggest数组映射到一个新的promises数组中。 findOne
返回包含查询未来结果的承诺。
Promise.all()
是一个静态方法,它接受一个promise数组,并返回一个单一的promise,当数组中的所有promise都成功解析时,它会解析。该承诺使用原始顺序中的所有已解析值的数组解析,这恰好正是您想要的。
.then(completeSend);
调用此.then
的承诺是从Promise.all()
返回的承诺,因此它等同于使用所有completeSend()
项的数组调用docs
承诺得到了解决。
答案 2 :(得分:1)
如果findOne
异步完成,并且看起来确实如此,那么forEach
将阻塞可能只有几分之一毫秒。 稍后,findOne
会在每次查询完成时调用每个回调。从阻塞的角度来看,考虑到findOne
异步完成的条件,该代码很好。
但是,代码有一个不同的问题:你假设回调将按顺序发生,通过这样做:
if (index === array.length - 1) {
completeSend(suggesterResults);
}
你不能做出这个假设,除非findOne
记录它(我查看了sails.js网站;找不到findOne
的任何文档而不是一个条目没有说什么的子弹清单。回调可能无序到达,例如,如果一次查找比之前的查找快一些。
相反,您希望跟踪您已收到的回复次数,并在您获得与请求相同的号码时致电completeSend
你做了,而不是依赖索引。
如果您在启动时suggesterResults
为空,并且在呼叫未完成时无法修改suggestions
,则可以使用其length
:
suggestions.forEach(function (element, index, array){
Suggester.findOne({
"id": element.suggester_id
},function(err,docs){
suggesterResults.push(docs);
console.log("I am adding to array: " + docs);
if (suggesterResults.length === array.length) {
completeSend(suggesterResults);
}
});
})
但如果其中任何一个警告都不对,那么你最好还是使用一个柜台:
var waitingon = 0;
suggestions.forEach(function (element, index, array){
++waitingon;
Suggester.findOne({
"id": element.suggester_id
},function(err,docs){
suggesterResults.push(docs);
console.log("I am adding to array: " + docs);
if (--waitingon === 0) {
completeSend(suggesterResults);
}
});
})
看起来像竞争条件,但它不是因为这是一个单线程环境。所有forEach
回调都会在第一次findOne
回调之前发生,因此waitingon
会在我们开始递减之前上升到适当的级别。 (这也允许suggestions
稀疏的可能性,这似乎不太可能。)