0

I was assuming that by using await I am making sure that the promise will get completed(it will wait at this statement until the promise is complete) before moving to the execution of next line. But seems I am wrong. I tried reading about it and going through with a lot of examples but still I am unable to understand why it doesnt work. Somehow, I am trying to relate these promises and chaining of it with Java's CompletableFutures but not able to completely understand it.

Not sure what is wrong with the below code. "productDetailsMap" is always coming as empty when invoking "getProductDetailsAndEnrichFulfillmentGroupIds".

async getProductDetailsAndEnrichFulfillmentGroupIds(authHeader: string,
                                                    styleCodes: string,
                                                    skuCodes: string[],
                                                    productPriceMap: Map<string, number>,
                                                    fulfillmentGroupIds: Set<number>): Promise<Map<string, Product>> {
                                                        
    const productDetailsMap: Map<string, Product> = new Map();
    const productSummaryDsResponse = await this.productDetailsDataLoader.getProductSummaryGroupLoader.load({
        authHeader: authHeader,
        styleCodes: styleCodes 
    });

    let promises = productSummaryDsResponse
        .ProductDetails
        .Results
        .map(result => {
            result
                .CustomAttributes
                .forEach(async customAttr => {
                    const product_attributes = JSON.parse(customAttr.Value);
                    let fulfillmentGroupId = 
                        (product_attributes.Details.FulfillmentGroupId 
                            && product_attributes.Details.FulfillmentGroupId.Value)
                        || -1;
                    fulfillmentGroupIds.add(fulfillmentGroupId);
                    await this
                            .buildProductFromAttributes(authHeader,
                                                        product_attributes,
                                                        skuCodes,
                                                        productPriceMap)
                            .then(product => productDetailsMap.set(product.styleSkuDetails.sku, product));
                })
        })
    
    return Promise
                .all(promises)
                .then(() => productDetailsMap);
  }

private async buildProductFromAttributes(authHeader: string,
                                         product_attributes: any,
                                         skuCodes: string[],
                                         productPriceMap: Map<string, number>): Promise<Product> {
    let product = new Product();

    [product.id, product.scode, product.title, product.isActive, product.styleSkuDetails, product.dUrl, product.iUrls] 
        =  await Promise.all([this.getProductId(product_attributes), //async function
                              this.getProductScode(product_attributes), //async function
                              this.getProductTitle(product_attributes), //async functions
                              this.isProductActive(product_attributes), //async functions
                              this.getProductStyleSkuDetails(authHeader,  product_attributes, skuCodes, productPriceMap), //async functions
                              this.getProductDUrl(product_attributes), //async functions
                              this.getProductIUrls(product_attributes)]); //async functions
                         
    return product;
}
Yash Khare
  • 355
  • 2
  • 10
  • 3
    `.forEach` does not *return* anything. You need to use `.map` or `.push` a promise into an array the promises you want to wait on (i.e. did you set a breakpoint and see what `promises` was?). – crashmstr Jun 06 '22 at 15:01
  • the callback in -> `productSummaryDsResponse.ProductDetails.Results.map(callback)` isnt returning a promise – andy mccullough Jun 06 '22 at 15:02
  • @crashmstr : I tried that as well, still it doesnt work. This is what i tried - inside forEach : promises.push(await this .buildProductFromAttributes(authHeader, product_attributes, skuCodes, productPriceMap) .then(product => productDetailsMap.set(product.styleSkuDetails.skuCode, product))); – Yash Khare Jun 06 '22 at 15:10
  • The problem seems to be inside "buildProductFromAttributes" function, coz the breakpoint is never reaching at the last line of return ie. : return product; It is however executing all the internal async functions which i kept in Promise.all - the breakpoint is reaching to the last statement of "getProductIUrls" function. But post that it never reaches to the last statement of buildProductFromAttributes: return product; – Yash Khare Jun 06 '22 at 15:12
  • You'll want `const promises = productSummaryDsResponse.ProductDetails.Results.flatMap(result => { return result.CustomAttributes.map(async customAttr => {…}); })` – Bergi Jun 06 '22 at 15:17
  • @Bergi : this doesnt work either. I have waisted 4hrs of mine trying to resolve this, and have looked into many stackoverflow questions and other blogs. I dont this this is a duplicate question of the above referred one. – Yash Khare Jun 06 '22 at 15:24
  • 1
    @YashKhare It definitely should fix the "*`productDetailsMap` is always coming as empty*" problem. If it doesn't, please `console.log(promises)` and tell us what you see, as requested by crasmstr. "*It never reaches to the last statement of `buildProductFromAttributes`*" - that sounds like a separate problem, which you might want to [ask a new question](https://stackoverflow.com/questions/ask) about. You'll need to post the code of all the methods you're invoking there, it sounds like one of them does not fulfill the promise it returns. – Bergi Jun 06 '22 at 15:44
  • You are absolutely right @Bergi . You seriously saved my day and made me happy before I was about to close my laptop with sadness. I just now found out that if one of the promise fails form the list of promises, it would rejects all and silently closes the promise.all . Unless I catch the error, which I didnt do in my foolishness. One of my promise was failing due to which i was getting "productDetailsMap" as null. It now works with my original code with forEach. – Yash Khare Jun 06 '22 at 15:56
  • No, that `forEach` code does *not* work. Maybe all your promises fulfill synchronously, or you use the `productDetailsMap` only later on, so you didn't notice? – Bergi Jun 06 '22 at 16:11

0 Answers0