我有一个对象(产品数据集),在一些对象中我有一组图像。对于我需要调用API来获取额外数据的每个图像,我想把它放回到原始对象中。
API调用是ID,这是有效的,我可以获取数据。
我认为我的异步性质存在问题而且我遗漏了一些东西(可能很明显!)......
谢谢!
function fetchImages(products) {
var deferred = Q.defer();
var product_updates = [];
products.forEach(function (product, idx, array) {
var image_updates = [];
if (product.images.length > 0)
{
//var id = product.images.mediaId;
//console.log(id);
image_updates = product.images.map(function(task) {
return {
image_urls: getImage(task.mediaId)
}
});
console.log(image_updates);
product_updates.push(image_updates);
}
else
{
product_updates.push(product);
}
if (idx === array.length - 1)
{
//console.log(stock_updates);
deferred.resolve(product_updates);
}
});
return deferred.promise;
}
这是缩短的“getImage”函数......
function getImage(id)
{
// Request options
var options = {
url: cfg.base_url + (cfg.base_url[cfg.base_url.length - 1] != '/' ? '/' : '') + 'api/media/' + id,
.........
};
request(options, function (error, response, body) {
// Check status code
if (response.statusCode >= 200 && response.statusCode <= 299) {
let result = JSON.parse(body);
console.log(result);
return result;
} else {
console.log("Failed to fetch images updates");
}
}
);
}
我也不确定“deferred.resolve(product_updates);”做得正确..似乎工作但不是100%肯定。
“image_update”的console.log返回:
[ { image_urls: undefined },
{ image_urls: undefined },
{ image_urls: undefined },
{ image_urls: undefined },
{ image_urls: undefined } ]
************修改了fetchImages()函数***********
function fetchImages(products) {
const getImagesForProduct = function(product) {
return product.images.map(function(task) {
return {
product: product,
image_urls: getImage(task.mediaId)
}
});
}
const product_updates = products.map(getImagesForProduct)
return new Promise(function(resolve, reject)
{
resolve(product_updates);
});
}
现在这更有说服力......但仍然没有得到所需的承诺?
答案 0 :(得分:1)
在你的例子中,getImage进行异步调用,因此应该返回一个promise。许多方式返回一个承诺 - 但原生承诺对象是最简单的(我怀疑你也可以用Q做这个 - 但是自从我使用该库以来已经很长时间了)。
function getImage(id)
{
// Request options
var options = {
url: cfg.base_url + (cfg.base_url[cfg.base_url.length - 1] != '/' ? '/' : '') + 'api/media/' + id,
.........
};
return new Promise(function(resolve, reject){
request(options, function (error, response, body) {
// Check status code
if (response.statusCode >= 200 && response.statusCode <= 299) {
let result = JSON.parse(body);
console.log(result);
resolve(result);
} else {
reject(error);
}
});
})
}
另一个功能也可以更有说服力地写出来。基本上:
// :: Product -> [{image_urls: Promise}]
const getImagesForProduct = function(product) {
return product.images.map(function(task) {
return {
image_urls: getImage(task.mediaId)
}
});
}
const product_updates = products.map(getImagesForProduct)
//=> [[{image_urls: Promise}]]
在这种情况下,您仍需要等待承诺才能解决。我怀疑你可以展平数组或重组转换以减少毛茸茸 - 但这取决于你的其他代码需要什么
答案 1 :(得分:1)
这是处理承诺的最终功能:
function fetchImages(products) {
const getImagesForProduct = function(product) {
if (product.images && product.images.length === 0) {
return Promise.resolve(product)
}
const getImagesPromiseTasks = product.images.map(task => getImage(task.mediaId));
return Promise.all(getImagesPromiseTasks)
.then(retrievedUrls => {
product.image_urls = retrievedUrls
return product
})
}
return Promise.all(products.map(getImagesForProduct))
}