2016-04-09 4 views
0

getBasketObjectと呼ばれる約束関数(using bluebird)を作成しました。この関数はバスケットを引数として期待し、新しいバスケットを返すよりも新しいbasketObjectを返します。ループ内のPromise関数の呼び出し方法とその戻り値の保存

basketObjectは、tax, total, shippingおよびproductItemsのようないくつかの変数を有する。今、productItemsオブジェクトにはprice, name, quantityプロパティがありますが、利用可能なのはproductImageLinkではありません。

productImageLink私は製品イメージオブジェクトを取得するエンドポイントに新しい非同期呼び出しを行います。 Image EndpointもPromiseとして実装されています。

ここでは、productLineItemsをループし、name, price, quantityのような属性の値を取得し、最後にget imageを呼び出します。

さて、私が追加した場合

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)

+0

呼び出しを行うのですか?してください'for 'ループの使用は配列ではなく、' key'を 'index'と呼び、' key'は配列のように見えないためです。 –

+0

@ t.niese:そのオブジェクトで、混乱を避けるために 'key'を使うように修正しました。 Thanks – RanRag

答えて

1

まずが有効でない複数の製品を持っている場合でも、それは1つの製品だけオブジェクトを取得し、見ることができますあなたはPromiseのためにresolveを複数回呼び出すので、一度だけ呼び出す必要があります。

stringをエラーとして使用することは避けてください。しかし、実際のエラー(約束だけでなく、常にjavascriptで)を使用してください。

for inループの代わりに、Object.keys(productLineItems)をPromiseチェーンに渡して、for inループの代わりに.eachを使用することができます。

あなたはproduct.getProductObjectによって導入された約束を返すことができます。

あなたはそのように書き換えることができます:

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; 
    }); 
}; 
+0

'promiseObj.each'は標準のES6' Promise'オブジェクトの一部ではありません。また、 '.each'が' Promise.all'のように順番に約束を順番に実行しているというもう一つの欠点はありますか? –

+0

@NickRassadin 'bluebird'が使用されているOP状態ですが、そうではありません。 –

+0

パーフェクト!約束の中で学ぶLot: – RanRag

1

あなたが約束を解決するためのループが終了しませんでした最初の反復で。しかし、完了するためには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)が本当に非同期は `配列やオブジェクトをproductLineItems`です

+0

'' then'のコールバック内で 'resolve'を呼び出すと、おそらくあなたは間違った方法を約束します。これはあなたのソリューションがうまくいかないことを意味するものではなく、プロミスその方法を使用すべきではありません。 「The Forgotten Promise」(http://taoofcode.net/promise-anti-patterns/#the-forgotten-promise:8f173b15e2d19515fdc8ce931ae539c0) –

+0

と似ていますが、間違っています。このメソッドは、すべての並行した約束が終了することを約束します。 他の方法では実行できません。 これは、忘れられた約束のパターンから遠いです。 –

+0

パターン 'return new Promise(function(resolve、reject)){/*...*/ Promise.all(asyncCalls).then(function(value){解決策(basketObj);}、関数(理由){拒否あなたの答えに書かれているものです。「新しいプロミスを返す」か、「プロミス。オール」が間違っているかのどちらかです。それが似ている理由です –

関連する問題