我也是Q和承诺的新手,并且几天来一直在努力解决这个问题。我正在尝试迭代一个可变长度的RECORDS数组,使用异步调用中每个记录的ID来检索OBJECT(在redis的情况下)。
我需要将RECORD中的一些数据与检索到的OBJECT中的一些数据结合起来,从这些组合对象中创建一个新数组,然后返回。
我的失败代码如下所示:
arrayOfThingRecords = [... an array of small objects, each with a 'thingid'...];
arrayOfCombinedObjects = [];
arrayOfThingRecords.forEach(function(thingRecord) {
Q.ninvoke(redisClient, "HGETALL", thingRecord.thingid)
.then((function (thingObject) {
combinedThingObject = {
thingStuffFromRecord: thingRecord.thingStuffFromRecord,
thingStuffFromObject: thingObject.thingStuffFromObject
};
}).done(function () {
arrayOfCombinedObjects.push(combinedThingObject)
}); //
}; // Then do stuff with arrayOfThingObjects...
我知道使用forEach
是错误的,因为它在promises返回之前执行。我一直在努力与Q.all()
和Q.settled()
合作,并建立一系列承诺等等,但我完全感到困惑,怀疑/希望我可能会比这需要更难是。
答案 0 :(得分:0)
请勿使用您手动填充的全局arrayOfCombinedObjects = []
。始终使用相应操作的结果值来解决您的承诺。例如,
Q.ninvoke(redisClient, "HGETALL", thingRecord.thingid)
.then(function(thingObject) {
return {
// ^^^^^^
thingStuffFromRecord: thingRecord.thingStuffFromRecord,
thingStuffFromObject: thingObject.thingStuffFromObject
};
});
成为该对象的承诺。
现在,使用Q.all
是正确的方法。它需要一个 promises数组,并将它们组合成一个包含所有结果数组的promise。所以我们需要构建一个promises数组 - 一个来自上面的这些对象的promise的数组。您可以使用forEach
次迭代和push
将数组放在一起,但使用map
会更容易。然后变成
var arrayOfThingRecords = [... an array of small objects, each with a 'thingid'...];
var arrayOfPromises = arrayOfThingRecords.map(function(thingRecord) {
return Q.ninvoke(redisClient, "HGETALL", thingRecord.thingid)
// ^^^^^^ let the promise be part of the new array
.then(function(thingObject) {
return {
thingStuffFromRecord: thingRecord.thingStuffFromRecord,
thingStuffFromObject: thingObject.thingStuffFromObject
};
});
});
Q.all(arrayOfPromises).then(function(arrayOfCombinedObjects) {
// Then do stuff with arrayOfThingObjects...
});