簡體   English   中英

如何在循環中調用Promise函數並保存其返回值

[英]How to call Promise function in loop and save its return value

我創建了一個承諾函數(using bluebird)稱為getBasketObject 此函數期望將basket作為參數,然后basketObject返回一個新的basketObject

basketObject具有一些變量,例如tax, total, shippingproductItems 現在,productItems對象中具有price, name, quantity屬性,但其中沒有productImageLink

為了獲得productImageLink我對端點進行了新的異步調用,這將使我獲得產品圖像對象。 Image Endpoint也被實現為Promise。

現在,我遍歷productLineItems並獲取name, price, quantity等屬性的值,最后調用以獲取圖像。

現在,如果我添加

basketObj["products"][productId]["productImageSrc"] = smallImage[0]; 我的對象從未修改過,在最終輸出中我沒有圖像鏈接。

發生這種情況是因為在異步調用發生之前我的getBasketObject返回了值。 為了解決這個問題,我添加了resolve(basketObj); 但這立即返回,並且不在循環中。

因此,遍歷我的產品並獲取所有產品的圖像鏈接的正確方法是什么。

exports.getBasketObject = function(basket) {

    return new Promise(function(resolve, reject){

        if (!basket){
            reject("Please give valid basket");
        }
        var basketObj = {};

        if ('order_total' in basket && basket.order_total) {
            basketObj.total = basket.order_total;
        } else if ('product_total' in basket && basket.product_total) {
            basketObj.total = basket.product_total;
        }

        var productLineItems = basket.product_items;
        basketObj["products"] = {};
        for (var key in productLineItems) {
            var productItem = productLineItems[key];
            var productId = productItem.product_id;

            //Async call to get Product Object
            product.getProductObject(productId).then(function(productObj){

                basketObj["products"][productId] = {};
                basketObj["products"][productId]['productQuantity'] = productItem.quantity;
                basketObj["products"][productId]["productName"] = productItem.item_text;
                basketObj["products"][productId]["productPrice"] = productItem.base_price;
                //If promise resolved, get images
                var imageObject = product.getProductImages(productObj[0]);
                var smallImage = imageObject['small'];
                basketObj["products"][productId]["productImageSrc"] = smallImage[0];
                resolve(basketObj); //Acts as a return
            });
        }

    });
};

如果我使用resolve(basketObject)我的最終對象看起來像

  {
    "total": 95.99,
    "tax": "N/A",
    "shipping": "N/A",
    "products": {
        "701642890706": {
            "productQuantity": 1,
            "productName": "Novelty Stitch Belted Cardigan",
            "productPrice": 95.99,
            "productImageSrc": "image.png"
        }
    }
}

您可以看到它僅獲得一個產品對象,即使productLineItems具有多個產品

首先,您的resolve(basketObj)無效,因為您多次為Promise調用resolve ,但是您只能調用一次。

您還應該避免將string用作錯誤,而應始終使用實際錯誤(不僅使用promise,而且始終使用javascript)。

而不是你的for in循環中,您可以通過Object.keys(productLineItems)在你的諾言鏈,然后使用.each而不是for in循環。

這樣,您可以返回product.getProductObject引入的Promise。

您可以這樣重寫它:

exports.getBasketObject = function(basket) {

  var basketObj = {};
  var productLineItems;

  return Promise.resolve(basket)
  .then(function(basket) {
    if( !basket ) {
      throw new Error("Please give valid basket");
    }
    productLineItems = basket.product_items;
  })
  .then(function() {
    if ( 'order_total' in basket && basket.order_total) {
      basketObj.total = basket.order_total;
    } else if ( 'product_total' in basket && basket.product_total) {
      basketObj.total = basket.product_total;
    }

    basketObj.products = {};

    //return the all keys of the productLineItems to be able to iterate over it using promises
    return Object.keys(productLineItems);
  })
  .each(function(key) {
    var productItem = productLineItems[key];
    var productId = productItem.product_id;
    basketObj.products[productId] = {};
    basketObj.products[productId].productQuantity = productItem.quantity;
    basketObj.products[productId].productName = productItem.item_text;
    basketObj.products[productId].productPrice = productItem.base_price;

    //Async call to get Product Object
    return product.getProductObject(productId).then(function(productObj) {
      //If promise resolved, get images
      var imageObject = product.getProductImages(productObj[0]);
      var smallImage = imageObject.small;
      basketObj.products[productId].productImageSrc = smallImage[0];
    });
  })
  .then(function() {
    //  return the basketObj after all  product.getProductObject resolved
    return basketObj;
  });
};

如果您不想使用.each ,則可以這樣編寫:

exports.getBasketObject = function(basket) {

  var basketObj = {};
  var productLineItems;

  return Promise.resolve(basket)
  .then(function(basket) {
    if( !basket ) {
      throw new Error("Please give valid basket");
    }
    productLineItems = basket.product_items;
  })
  .then(function() {
    if ( 'order_total' in basket && basket.order_total) {
      basketObj.total = basket.order_total;
    } else if ( 'product_total' in basket && basket.product_total) {
      basketObj.total = basket.product_total;
    }

    basketObj.products = {};

    var promises = [];

    Object.keys(productLineItems).forEach(function(key) {
      var productItem = productLineItems[key];
      var productId = productItem.product_id;
      basketObj.products[productId] = {};
      basketObj.products[productId].productQuantity = productItem.quantity;
      basketObj.products[productId].productName = productItem.item_text;
      basketObj.products[productId].productPrice = productItem.base_price;


      promises.push(
        product.getProductObject(productId).then(function(productObj) {
          //If promise resolved, get images
          var imageObject = product.getProductImages(productObj[0]);
          var smallImage = imageObject.small;
          basketObj.products[productId].productImageSrc = smallImage[0];
        });
      );
    });

    return Promise.all(promises);
  })
  .then(function() {
    return basketObj;
  });
};

循環未完成,因為您在第一次迭代中解決了諾言。 但是您需要等待product.getProductObject所有異步調用完成。 在這里Promise.all可以提供幫助。

...
var asycnCalls = [];
for (var index in productLineItems) {

    ...
    //Async call to get Product Object
    asyncCalls.push(
        product.getProductObject(productId).then(function(productObj){
            //If promise resolved, get images
            var imageObject = product.getProductImages(productObj[0]);
            var smallImage = imageObject['small'];
            basketObj["products"][productId]["productImageSrc"] = smallImage[0];                
        })
    )
} //end of for loop

Promise.all(asyncCalls).then(function(value) { 
    resolve(basketObj); //Acts as a return
}, function(reason) {
    reject(reason);
});

並且請確保product.getProductObject(productId)確實進行了異步調用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM