【问题标题】:Promises.all with additional valuesPromises.all 带有附加值
【发布时间】:2017-10-13 14:47:05
【问题描述】:

对 promises 不熟悉,想学习。 我有这个 shopIds 数组:

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

和一个外部承诺调用

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

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

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

稍后,我的“包装承诺”应该返回完成的 shopAndProductsArray。

我当前的代码(节点,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 相同数量的条目,但数组项未定义。我可能应该先将 Promise 放入一个数组中,然后在 Promise.all 中处理它们,但那时我失去了对 Promise 所属商店 ID 的引用。

我阅读了许多有关迭代和承诺的其他示例,并尝试了许多其他方法,但似乎我还没有完全理解此时所谓的什么。我确定以我的方式填充 promises 数组是错误的,但我不知道如何调用 Promise.all。

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

  1. 我应该如何遍历 shopIds,调用 promise 每个?
  2. 如何在 promise 返回产品列表后保留 shopId?
  3. 处理完所有 shopId 后,如何返回 shopId 和产品数组?

提前感谢您的帮助。

编辑: 非常感谢,justelouise 和 Felix Kling。我知道我把事情复杂化了,但不能把手指放在哪里。感谢您的示例,我现在了解我所缺少的内容。 我认为您的答案基本上是相同的,并且都得到了彻底的解释。我给 justelouise 打了接受复选标记,因为她似乎是第一个,而且 Felix Kling 的声望略高 O_o。

【问题讨论】:

  • 您正在调用shopsAndProductsArray.push(exchangeInfoObject);,但您创建的对象已分配给shopInfoObject
  • 您的所有承诺都解析为undefined - 因为您的.then(products => 不返回任何内容......这就是为什么shopsAndProductsArray 是一个未定义的function (shopsAndProductsArray) 数组
  • 注意:您的const shopsAndProductsArray = []; 永远不会用于任何事情
  • 顺便说一句——不包括console.logging,var updateProducts = Promise.all(['shop1', 'shop2','shop3'].map(id => getProducts(id, 'products').then(products => ({id, products}))));可能就是你想要的
  • @Felix,我更正了代码。

标签: javascript node.js promise es6-promise


【解决方案1】:

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

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

Promise.all 返回一个在您通过 map 函数遍历数组时创建的承诺数组,其中在 getProducts 中为每个商店 ID 执行调用。返回产品数据后,您仍然可以访问相应的商店 id 并返回一个由 id 和结果组成的新对象

return {
  id: shopId,
  products,
};

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

【讨论】:

  • 这个解决方案非常适合我的需求!我有一个从数据库中提取的 ID 数组,我正在循环它们以创建数组或承诺传递给 Promise.all,但无法知道哪些结果映射到了哪个 ID。您的解决方案解决了这个问题!
【解决方案2】:

您的代码可以大大简化为:

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

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

由于Promise.all 已经返回了一个promise,所以没有必要在它周围加上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)。

【讨论】:

    猜你喜欢
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    相关资源
    最近更新 更多