2017-10-13 28 views
0

諾言,想學習。 我有這個數組shopIds的:Promises.all附加值

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

和外部承諾呼叫

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

不幸的是,承諾不返回shopId,只是產品,所以我必須以某種方式保持shopId和一旦承諾完成,將其與產品一起存儲。 我目前的做法是調用每個shopId的承諾,並添加結果中的每個承諾調用到shopsAndProductsArray這樣的:

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

後來,我的「包裝的承諾」應該返回成品shopsAndProductsArray。

我當前的代碼(節點,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.all中處理它們,但是在那個時候,我失去了承諾所屬的商店ID的參考。

我讀了很多關於迭代和承諾的其他例子,並嘗試了許多其他方法,但似乎我並沒有完全理解在哪一點上稱爲什麼。我確信按照我做的方式填充promise數組是錯誤的,但我沒有更好的想法如何調用Promise.all。

我想我可以縮小我的問題到:

  1. 我應該如何遍歷shopIds,呼籲每個 的承諾?
  2. 一旦承諾返回產品清單,我如何保留shopId?
  3. 一旦所有shopIds都被處理完後,如何返回shopIds和product的數組?

在此先感謝您的幫助。

編輯: 非常感謝,justelouise和Felix Kling。我知道我過於複雜,但無法把我的手指放在哪裏。現在我明白我缺少的東西,感謝你的例子。 我認爲你的答案基本上是平等的,並且都被徹底解釋。我將接受的選中標記作爲justelouise,因爲她看起來是第一個,而Felix Kling的聲望略高於O_o。

+0

您正在調用'shopsAndProductsArray.push(exchangeInfoObject);',但您創建的對象已分配給'shopInfoObject'。 –

+0

所有的承諾都解析爲'undefined' - 因爲你的'.then(products =>'不會返回任何東西......這就是爲什麼'shopsAndProductsArray'是一個未定義函數的數組('''') –

+0

注意:你的'const shopsAndProductsArray = [];'從不用於任何東西 –

回答

1

我認爲你可以簡化你的功能,例如:

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

Promise.all其中的getProducts調用返回創建爲你迭代通過地圖功能的陣列通承諾的數組爲每個商店ID執行。一旦返回的產品數據,你仍然有對應的店鋪ID爲它的訪問,並返回由該ID和一個新的對象,結果

return { 
    id: shopId, 
    products, 
}; 

最後,Promise.all返回包含返回值的數組每個承諾都在其中執行。

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)。