node.js - 使用.map来丰富对象

时间:2018-03-31 12:19:17

标签: node.js

我有一个对象(产品数据集),在一些对象中我有一组图像。对于我需要调用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);
    });

}

现在这更有说服力......但仍然没有得到所需的承诺?

2 个答案:

答案 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))

}