我正在尝试在数组上运行一些数据库查询(使用sails.js),并在查询返回时执行某些操作。我认为最好的方法是使用for循环并解析promises async,一旦它们全部解决,继续。但是,只有我的数组中的最后一个promise才会解析,并且它会多次解析,因为在每个'User.findOne ...'然后函数中,索引是array.length-1。
我的问题:
我已检查的主要教程
感谢您的帮助!
我的简化代码:
functionWhichReturnsPromise()
.then(function(user){
var promises = [];
Q.try(function(){
for (var index in array) {
var fbid = array[index];// Get fbid from array
promises.push(Q.defer().promise); // Add promise to promise array
// Find userid from fbid; resolve respective promise when finished
User.findOne({facebook_id: fbid}).then(function(userSeen){
promises[index].resolve(userSeen.id);
sails.log('resolved where id=' + userSeen.id); // correct
sails.log('resolved where index=' + index); // PROBLEM: always last index
});
}
}).then(function(){
// For debugging purposes
Q.delay(1000).then(function(){
sails.log(promises[0]); // Unresolved
sails.log(promises[1]); // Unresolved
sails.log(promises[2]); // Only last promise in array is resolved
});
// When the userids have been extracted from above (promises fulfilled)...
Q.all(promises).then(function(seenids){
// Do stuff here (Doesn't get here)
});
});
});
答案 0 :(得分:2)
在Javascript中,变量的范围是函数而不是花括号。
因此,在下面的代码中,var index
的范围不是for循环的花括号,范围实际上是for循环存在的函数。
Q.try(function(){
for (var index in array) {
var fbid = array[index];// Get fbid from array
promises.push(Q.defer().promise); // Add promise to promise array
// Find userid from fbid; resolve respective promise when finished
User.findOne({facebook_id: fbid}).then(function(userSeen){
promises[index].resolve(userSeen.id);
sails.log('resolved where id=' + userSeen.id); // correct
sails.log('resolved where index=' + index); // PROBLEM: always last index
});
}
})
在for循环中,您调用异步函数,在您的情况下调用其mongodb调用(findOne
)。
您应该始终假设这些异步函数可以运行任意数毫秒(取决于函数)。但总的来说,通常循环将在异步函数运行之前完成。即使在这些函数开始运行之前,你的for循环也会触发所有这些异步函数。问题是所有那些异常功能区域仍然指向该变量index
。并且该变量对所有变量都是通用的,因为index
在外部函数的范围内。
由于Javascript中的闭包,这是一个问题。要解决这个问题,我们需要使用更多的闭包。
关于闭包主题的资源很多,你可以谷歌。但请通过MDN's description of it。
如果你在循环中的另一个函数中捕获index
的值,那么你将会很高兴。
以下是我建议的解决方案。虽然我还没有测试过,但你明白了。
Q.try (function () {
array.forEach( function(ele, idx, array) {
(function(index) {
var fbid = array[index]; // Get fbid from array
promises.push(Q.defer().promise); // Add promise to promise array
// Find userid from fbid; resolve respective promise when finished
User.findOne({
facebook_id : fbid
}).then(function (userSeen) {
promises[index].resolve(userSeen.id);
sails.log('resolved where id=' + userSeen.id); // correct
sails.log('resolved where index=' + index); // PROBLEM: always last index
});
})(idx);
})
})
希望这有帮助。
另请注意: it is incorrect to use for...in for iterating through arrays。