如何在循环中调用 Promise 函数并保存其 return 值
How to call Promise function in loop and save its return value
我创建了一个名为 getBasketObject
的承诺函数(using bluebird)
。此函数需要一个篮子作为参数,而不是 return 一个新的 basketObject
。
basketObject
有一些变量,例如 tax, total, shipping
和 productItems
。现在,productItems 对象有 price, name, quantity
个可用属性,但没有 productImageLink
个可用属性。
为了获得 productImageLink
,我对端点进行了新的异步调用,这将使我获得产品图像对象。 Image Endpoint
也作为 Promise 实现。
现在,我遍历 productLineItems
并获取 name, price, quantity
等属性的值,最后调用获取图像。
现在,如果我添加
basketObj["products"][productId]["productImageSrc"] = smallImage[0];
我的对象从未被修改,在最终输出中我没有得到图像 link。
发生这种情况是因为在异步调用发生之前我的 getBasketObject
returned 值。为了解决这个问题,我添加了 resolve(basketObj);
,但是这个 return 立即退出了循环。
那么,遍历我的产品项并获取所有产品的图像 link 的正确方法是什么。
exports.getBasketObject = function(basket) {
return new Promise(function(resolve, reject){
if (!basket){
reject("Please give valid basket");
}
var basketObj = {};
if ('order_total' in basket && basket.order_total) {
basketObj.total = basket.order_total;
} else if ('product_total' in basket && basket.product_total) {
basketObj.total = basket.product_total;
}
var productLineItems = basket.product_items;
basketObj["products"] = {};
for (var key in productLineItems) {
var productItem = productLineItems[key];
var productId = productItem.product_id;
//Async call to get Product Object
product.getProductObject(productId).then(function(productObj){
basketObj["products"][productId] = {};
basketObj["products"][productId]['productQuantity'] = productItem.quantity;
basketObj["products"][productId]["productName"] = productItem.item_text;
basketObj["products"][productId]["productPrice"] = productItem.base_price;
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject['small'];
basketObj["products"][productId]["productImageSrc"] = smallImage[0];
resolve(basketObj); //Acts as a return
});
}
});
};
如果我使用 resolve(basketObject)
我的最终对象看起来像
{
"total": 95.99,
"tax": "N/A",
"shipping": "N/A",
"products": {
"701642890706": {
"productQuantity": 1,
"productName": "Novelty Stitch Belted Cardigan",
"productPrice": 95.99,
"productImageSrc": "image.png"
}
}
}
即使 productLineItems
有多个产品,您也可以看到它只获取一个产品对象
首先你的resolve(basketObj)
是无效的,因为你多次为你的Promise调用resolve
,但你必须只调用一次。
您还应避免将 string
用作错误,但始终使用真正的错误(不仅是承诺,而且始终在 javascript 中)。
您可以在 Promise 链中传递 Object.keys(productLineItems)
而不是 for in
循环,然后使用 .each
而不是 for in
循环。
这样你就可以 return product.getProductObject
引入的 Promise。
你可以这样重写:
exports.getBasketObject = function(basket) {
var basketObj = {};
var productLineItems;
return Promise.resolve(basket)
.then(function(basket) {
if( !basket ) {
throw new Error("Please give valid basket");
}
productLineItems = basket.product_items;
})
.then(function() {
if ( 'order_total' in basket && basket.order_total) {
basketObj.total = basket.order_total;
} else if ( 'product_total' in basket && basket.product_total) {
basketObj.total = basket.product_total;
}
basketObj.products = {};
//return the all keys of the productLineItems to be able to iterate over it using promises
return Object.keys(productLineItems);
})
.each(function(key) {
var productItem = productLineItems[key];
var productId = productItem.product_id;
basketObj.products[productId] = {};
basketObj.products[productId].productQuantity = productItem.quantity;
basketObj.products[productId].productName = productItem.item_text;
basketObj.products[productId].productPrice = productItem.base_price;
//Async call to get Product Object
return product.getProductObject(productId).then(function(productObj) {
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject.small;
basketObj.products[productId].productImageSrc = smallImage[0];
});
})
.then(function() {
// return the basketObj after all product.getProductObject resolved
return basketObj;
});
};
如果不想用.each
可以这样写:
exports.getBasketObject = function(basket) {
var basketObj = {};
var productLineItems;
return Promise.resolve(basket)
.then(function(basket) {
if( !basket ) {
throw new Error("Please give valid basket");
}
productLineItems = basket.product_items;
})
.then(function() {
if ( 'order_total' in basket && basket.order_total) {
basketObj.total = basket.order_total;
} else if ( 'product_total' in basket && basket.product_total) {
basketObj.total = basket.product_total;
}
basketObj.products = {};
var promises = [];
Object.keys(productLineItems).forEach(function(key) {
var productItem = productLineItems[key];
var productId = productItem.product_id;
basketObj.products[productId] = {};
basketObj.products[productId].productQuantity = productItem.quantity;
basketObj.products[productId].productName = productItem.item_text;
basketObj.products[productId].productPrice = productItem.base_price;
promises.push(
product.getProductObject(productId).then(function(productObj) {
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject.small;
basketObj.products[productId].productImageSrc = smallImage[0];
});
);
});
return Promise.all(promises);
})
.then(function() {
return basketObj;
});
};
循环未完成,因为您在第一次迭代时就解决了您的承诺。但是您需要等待 product.getProductObject
的所有异步调用完成。这里 Promise.all
提供帮助。
...
var asycnCalls = [];
for (var index in productLineItems) {
...
//Async call to get Product Object
asyncCalls.push(
product.getProductObject(productId).then(function(productObj){
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject['small'];
basketObj["products"][productId]["productImageSrc"] = smallImage[0];
})
)
} //end of for loop
Promise.all(asyncCalls).then(function(value) {
resolve(basketObj); //Acts as a return
}, function(reason) {
reject(reason);
});
并且请确保 product.getProductObject(productId)
确实进行了异步调用
我创建了一个名为 getBasketObject
的承诺函数(using bluebird)
。此函数需要一个篮子作为参数,而不是 return 一个新的 basketObject
。
basketObject
有一些变量,例如 tax, total, shipping
和 productItems
。现在,productItems 对象有 price, name, quantity
个可用属性,但没有 productImageLink
个可用属性。
为了获得 productImageLink
,我对端点进行了新的异步调用,这将使我获得产品图像对象。 Image Endpoint
也作为 Promise 实现。
现在,我遍历 productLineItems
并获取 name, price, quantity
等属性的值,最后调用获取图像。
现在,如果我添加
basketObj["products"][productId]["productImageSrc"] = smallImage[0];
我的对象从未被修改,在最终输出中我没有得到图像 link。
发生这种情况是因为在异步调用发生之前我的 getBasketObject
returned 值。为了解决这个问题,我添加了 resolve(basketObj);
,但是这个 return 立即退出了循环。
那么,遍历我的产品项并获取所有产品的图像 link 的正确方法是什么。
exports.getBasketObject = function(basket) {
return new Promise(function(resolve, reject){
if (!basket){
reject("Please give valid basket");
}
var basketObj = {};
if ('order_total' in basket && basket.order_total) {
basketObj.total = basket.order_total;
} else if ('product_total' in basket && basket.product_total) {
basketObj.total = basket.product_total;
}
var productLineItems = basket.product_items;
basketObj["products"] = {};
for (var key in productLineItems) {
var productItem = productLineItems[key];
var productId = productItem.product_id;
//Async call to get Product Object
product.getProductObject(productId).then(function(productObj){
basketObj["products"][productId] = {};
basketObj["products"][productId]['productQuantity'] = productItem.quantity;
basketObj["products"][productId]["productName"] = productItem.item_text;
basketObj["products"][productId]["productPrice"] = productItem.base_price;
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject['small'];
basketObj["products"][productId]["productImageSrc"] = smallImage[0];
resolve(basketObj); //Acts as a return
});
}
});
};
如果我使用 resolve(basketObject)
我的最终对象看起来像
{
"total": 95.99,
"tax": "N/A",
"shipping": "N/A",
"products": {
"701642890706": {
"productQuantity": 1,
"productName": "Novelty Stitch Belted Cardigan",
"productPrice": 95.99,
"productImageSrc": "image.png"
}
}
}
即使 productLineItems
有多个产品,您也可以看到它只获取一个产品对象
首先你的resolve(basketObj)
是无效的,因为你多次为你的Promise调用resolve
,但你必须只调用一次。
您还应避免将 string
用作错误,但始终使用真正的错误(不仅是承诺,而且始终在 javascript 中)。
您可以在 Promise 链中传递 Object.keys(productLineItems)
而不是 for in
循环,然后使用 .each
而不是 for in
循环。
这样你就可以 return product.getProductObject
引入的 Promise。
你可以这样重写:
exports.getBasketObject = function(basket) {
var basketObj = {};
var productLineItems;
return Promise.resolve(basket)
.then(function(basket) {
if( !basket ) {
throw new Error("Please give valid basket");
}
productLineItems = basket.product_items;
})
.then(function() {
if ( 'order_total' in basket && basket.order_total) {
basketObj.total = basket.order_total;
} else if ( 'product_total' in basket && basket.product_total) {
basketObj.total = basket.product_total;
}
basketObj.products = {};
//return the all keys of the productLineItems to be able to iterate over it using promises
return Object.keys(productLineItems);
})
.each(function(key) {
var productItem = productLineItems[key];
var productId = productItem.product_id;
basketObj.products[productId] = {};
basketObj.products[productId].productQuantity = productItem.quantity;
basketObj.products[productId].productName = productItem.item_text;
basketObj.products[productId].productPrice = productItem.base_price;
//Async call to get Product Object
return product.getProductObject(productId).then(function(productObj) {
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject.small;
basketObj.products[productId].productImageSrc = smallImage[0];
});
})
.then(function() {
// return the basketObj after all product.getProductObject resolved
return basketObj;
});
};
如果不想用.each
可以这样写:
exports.getBasketObject = function(basket) {
var basketObj = {};
var productLineItems;
return Promise.resolve(basket)
.then(function(basket) {
if( !basket ) {
throw new Error("Please give valid basket");
}
productLineItems = basket.product_items;
})
.then(function() {
if ( 'order_total' in basket && basket.order_total) {
basketObj.total = basket.order_total;
} else if ( 'product_total' in basket && basket.product_total) {
basketObj.total = basket.product_total;
}
basketObj.products = {};
var promises = [];
Object.keys(productLineItems).forEach(function(key) {
var productItem = productLineItems[key];
var productId = productItem.product_id;
basketObj.products[productId] = {};
basketObj.products[productId].productQuantity = productItem.quantity;
basketObj.products[productId].productName = productItem.item_text;
basketObj.products[productId].productPrice = productItem.base_price;
promises.push(
product.getProductObject(productId).then(function(productObj) {
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject.small;
basketObj.products[productId].productImageSrc = smallImage[0];
});
);
});
return Promise.all(promises);
})
.then(function() {
return basketObj;
});
};
循环未完成,因为您在第一次迭代时就解决了您的承诺。但是您需要等待 product.getProductObject
的所有异步调用完成。这里 Promise.all
提供帮助。
...
var asycnCalls = [];
for (var index in productLineItems) {
...
//Async call to get Product Object
asyncCalls.push(
product.getProductObject(productId).then(function(productObj){
//If promise resolved, get images
var imageObject = product.getProductImages(productObj[0]);
var smallImage = imageObject['small'];
basketObj["products"][productId]["productImageSrc"] = smallImage[0];
})
)
} //end of for loop
Promise.all(asyncCalls).then(function(value) {
resolve(basketObj); //Acts as a return
}, function(reason) {
reject(reason);
});
并且请确保 product.getProductObject(productId)
确实进行了异步调用