forEach 的简单承诺
Posted
技术标签:
【中文标题】forEach 的简单承诺【英文标题】:Simple promise with forEach 【发布时间】:2016-08-19 22:54:16 【问题描述】:我正在尝试使用 Promise 来等待异步 forEach:
var forEachMatch = function(matches)
var deferred = Q.defer();
matches.forEach(function(match)
var messages = Message.find('matchid': match._id, function(err,messages)
if(err)
console.log(err);
else
console.log(match._id);
);
);
return deferred.promise;
;
在这里使用:
forEachMatch(matches, function()
console.log("DONE");
res.status(200).json(
bob,
matches: matches,
);
);
我的控制台输出如下:所有match._id
都已打印,但DONE
从未打印。
有解决办法吗?我从 node 和 promises 开始,所以我肯定会忘记一些东西,但我看不到什么。
感谢您的任何回答。
编辑
最终的解决方案,感谢 Alexander Mac:
var forEachMatch = function(matches)
var promises = matches.map(match =>
return Message
.find('matchid': match._id)
.populate(
path: 'fromUser toUser',
select: 'id firstname'
)
.then(messages => [match, messages])
.catch(err =>
console.log("Error in forEachMatch");
return [match, null];
);
);
return Q.all(promises);
forEachMatch(matches)
.then(messagesByMatch =>
res.status(200).json(
user,
messagesByMatch: messagesByMatch
);
);
【问题讨论】:
你的 forEachMatch 方法只接受一个参数,所以你的 DONE 回调永远不会被调用 【参考方案1】:在您的情况下,最好使用Q.all
,它接受承诺或值的数组:
var forEachMatch = function(matches)
var promises = matches.map(match =>
return Message
.find('matchid': match._id)
.then(messages => [match, messages]);
);
return Q.all(promises);
forEachMatch(matches)
.then(results =>
console.log("DONE", results);
res.status(200).json(
bob,
matches: matches,
);
);
https://github.com/kriskowal/q/wiki/API-Reference#promiseall
【讨论】:
这种解决方案是否可以在 .map 函数结束时返回数据?我在matches.map
的每次迭代中处理一个变量,并希望在最后返回它。
是的,这是可能的,但是您想要返回什么?所有match._id
?
请查看我对您答案的编辑,我想处理错误并返回结果。
请将其添加为评论。
var forEachMatch = function(matches) var result = []; var promises = matches.map(match => Message.find('matchid': match._id, function(error, messages) if(error) // return error else result.push([match,messages]); )); return Q.all(promises);
【参考方案2】:
您正在返回一个延迟的承诺,并且该承诺没有得到解决或拒绝。请尝试以下操作:
var forEachMatch = function(matches)
var deferred = Q.defer();
matches.forEach(function(match)
var messages = Message.find('matchid': match._id, function(err,messages)
if(err)
deferred.reject(err);
else
deferred.resolve(match._id);
);
);
return deferred.promise;
;
调用者会变成
forEachMatch(matches).then(id=>
console.log("done succesffuly found");
).catch(err=>
console.log("not found error",err);
).done(()=>
console.log("done")
);
【讨论】:
.then
和 .done
闭包有什么区别? .then
闭包是否在 matches.forEach
的每次迭代中调用?【参考方案3】:
您从未调用过promise.reject
或promise.reject
方法。此外,对异步操作做出了承诺,而 forEach 则没有。
这是一个肮脏的修复:
var forEachMatch = function(matches)
var deferred = Q.defer();
// make the foreach asynchronous
setTimeout(function()
matches.forEach(function(match)
// do stuff
);
// notify end
deferred.resolve();
, 0);
return deferred.promise;
;
// use .then
forEachMatch(matches).then(function()
console.log("DONE");
);
【讨论】:
那么在执行其他操作(例如发送请求结果)之前等待我的 forEach 结束的最佳方法是什么?以上是关于forEach 的简单承诺的主要内容,如果未能解决你的问题,请参考以下文章