我有一个函数,我只想在foreach完成时解决..我使用q和mongoose这是大写的东西所指的,基本上我想首先创建一组项目,然后运行一个foreach完成后的功能。
function createItems() {
var deferred = Q.defer();
var itemsArray = [{ 'name' : 'spade' }, { 'name' : 'bucket' } , { 'name' : 'sand'}];
itemsArray.forEach(function(itemObj) {
var item = new Item(itemObj); // forces it to use a schema (dont worry)
Item.findOneAndUpdate({
url: item.short_name
}, item, {
upsert: true
}, function(err) {
if (!err) {
console.log(item.name + ' created.');
deferred.resolve();
} else {
deferred.reject(new Error(err));
}
});
});
return deferred.promise;
}
createItems()
.then(function() {
console.log('All items done.');
});
所以我希望在控制台上看到类似的内容;
创建了spade项目 铲斗项目已创建 沙子项目创建 所有项目都已完成。
答案 0 :(得分:3)
快速放弃:您的数组存在语法问题,它包含一个多次尝试写入name
的对象。我假设您打算拥有一个对象数组,每个对象都有一个name
。
基本上,您的方法失败是因为您在第一个实例上解决了您的承诺。您需要一个代表多个异步调用完成的承诺。标准的方法是将 promises数组传递给像Q.all
/ Bluebird.all
/ Promise.all
这样的库函数。 all
函数接受一系列promise并返回一个结果数组的promise。它会在所有承诺解决时解决,或者当任何一个承诺拒绝时拒绝。
function createItems() {
var promisesForUpdatedDocs = [];
var itemsArray = [
{ name: 'spade'},
{ name: 'bucket'},
{ name: 'sand'}
];
itemsArray.forEach(function(itemObj) {
var item = new Item(itemObj);
var updatedDocPromise = Item.findOneAndUpdate({
url: item.short_name
}, item, {
upsert: true
}).exec(); // returns an mPromise
promisesForUpdatedDocs.push(Q(updatedDocPromise)); // using Q to turn the mPromise to a Q promise, and adding it to an array
});
return Q.all(promisesForUpdatedDocs); // creates a promise for array of results (from array of promises)
}
createItems()
.then(function(items) {
console.log('All items done:', items);
}).catch(console.log); // never forget to handle errors! Always `return` or `catch` a promise chain.