Promises.all附加值

时间:2017-10-13 05:34:12

标签: javascript node.js promise es6-promise

承诺的新意,想学习。 我有这一系列的shopIds:

let shopIdsArray = ['shop1','shop2','shop3'];

和外部承诺电话

getProducts(shopId, 'products') //promise returns the products of this shop

不幸的是,承诺不会返回shopId,只返回产品,因此我必须以某种方式保留shopId并在承诺完成后将其与产品一起存储。 我目前的做法是用每个shopId调用promise,并将每个promise调用的结果添加到storesAndProductsArray中,如下所示:

shopsAndProductsArray.push({
    "id":shopId,
    "products":products
}); 

稍后,我的“包装承诺”应该返回已完成的商店和产品阵列。

我当前的代码(节点,ES6)如下所示:

updateProducts = new Promise(

    function (resolve, reject) {
        let shopIdsArray = ['shop1','shop2','shop3'];
        const shopsAndProductsArray = [];
        let promisesArray = [];

        shopIdsArray.forEach((shopId) => {
            let promise = getProducts(shopId, 'products')
                    .then((products) => {
                        const shopInfoObject = {
                                 "id":shopId,
                                 "products":products
                        };
                        console.log("sio: ",shopInfoObject); //prints shopIds and products fine.
                        shopsAndProductsArray.push(shopInfoObject);
                        promisesArray.push(promise);
                    });

        });

        Promise.all(promisesArray)
            .then(function (shopsAndProductsArray) {
                resolve(shopsAndProductsArray); //the shopsAndProductsArray is undefined?
            });
    }
);

在解析时,shopsAndProductsArray是......不为空,但由与shopIdsArray相同数量的条目组成,但数组项未定义。我可能应该首先将promises放入数组中,然后在Promise.all中对它们进行处理,但在那时我丢失了对promise所属的商店ID的引用。

我阅读了许多关于迭代和承诺的其他例子,并尝试了许多其他方法,但似乎我还没有完全理解在哪一点上被称为什么。我确定以我的方式填充promises数组是错误的,但我不知道如何调用Promise.all。

我想我可以将问题缩小到:

  1. 我应该如何遍历shopIds,用来调用promise 每个?
  2. 一旦承诺返回产品列表,我如何保留shopId?
  3. 如果所有shopIds都已处理完,我该如何退回shopIds和产品数组?
  4. 提前感谢您的帮助。

    编辑: 非常感谢justelouise和Felix Kling。我知道我的事情过于复杂,但无法将我的手指放在哪里。由于你的例子,我现在明白了我所缺少的东西。 我认为你的答案基本上是平等的并且都得到了彻底解释我给justelouise提供了接受复选标记,因为她似乎是第一名,而Felix Kling的名声稍微有点O_o。

2 个答案:

答案 0 :(得分:1)

我认为你可以简化你的功能:

return Promise.all(shopIdsArray.map(shopId => {
  return getProducts(shopId).then((products) => {
    return {
      id: shopId,
      products,
    };
  });
}));

Promise.all 返回一个promises数组,当你通过map函数迭代到数组时,在每个商店id执行 getProducts 调用。返回产品数据后,您仍然可以访问相应的商店ID,并返回包含ID和结果的新对象

return {
  id: shopId,
  products,
};

最后,Promise.all返回一个数组,其中包含在其中执行的每个promise的返回值。

答案 1 :(得分:1)

您的代码可以简化为:

updateProducts = Promise.all(
  ['shop1','shop2','shop3'].map(
    id => getProducts(id, 'products').then(products => ({id, products}))
  )
);

这与你的方法完全相同,只是不那么冗长。

由于Promise.all已经返回了一个承诺,因此无需在其周围添加new Promise(...)

如果要将数组的每个元素转换为其他元素,则Array#map是一种更有用的方法。它将传递的回调应用于数组的每个元素,并返回其返回值的数组。在您的情况下,您想为每个商店ID创建一个Promise,这就是

['shop1','shop2','shop3'].map(id => getProducts(id, 'products'))

确实

现在,既然你不仅想获得产品而且还要获得ID,我们必须稍微修改一下getProducts的结果,这就是

.then(products => ({id, products}))

一样。这没什么特别的。我们只返回一个包含两个属性idproducts的对象,而不仅仅是products数组。

使用Promise.allArray#map,您无需“手动”跟踪承诺(promisesArray)和结果(shopsAndProductsArray)。