0

In my application I have a function that returns a promise. What I do inside that function is, waiting for an image in DOM to be available and extract that element to generate base64 data of it.

getCodesOfOneMerchant(merchantDataEntry: MerchantData) {

    var codesOfMerchant = [];

    return new Promise(async (resolve, reject) => {

      for (let index = 0; index < merchantDataEntry.qrPayloadList.length; index++) {

        const value = merchantDataEntry.qrPayloadList[index];
        const payLoad = value.qrPayload
        this.qrvalue = payLoad;

        while (!document.querySelector(".qrcode img")) {
          await new Promise(r => setTimeout(r, 500));
          console.log("waiting for qr");
        }
        console.log("QR element is available");
        const qrEle = document.getElementById('qrcode');
        let imgBase64Data = this.getBase64Image(qrEle.firstChild.firstChild);

        console.log('Base64 = ' + imgBase64Data);

        var qrName = merchantDataEntry.serviceName + "-" + value.branch + "-" + value.mobile;

        let userQr: UserQr = new UserQr();
        userQr.name = qrName;
        userQr.qr = imgBase64Data;

        codesOfMerchant.push(userQr);
        console.log('1')
        
        if (index == merchantDataEntry.qrPayloadList.length - 1) {
          resolve();
        }
      }
      console.log('2')
      console.log('Returning data = ' + JSON.stringify(codesOfMerchant));
      return codesOfMerchant;

    });
}

Following is the function which calls above one.

async downloadQrCodesOfAllSelectedMerchants() {

    var qrCodesForAllMerchants = [];

    const filteredData = this.merchantDataList.filter(entry => entry.qrSelected);

    const promises = filteredData.map(async (value) => {
      const qrCodesOfMerchant = await this.getCodesOfOneMerchant(value);
      return qrCodesOfMerchant;
    });

    const qrCodesOfAll = await Promise.all(promises);

    console.log('HELLO');

    console.log(qrCodesOfAll); // this prints undefined

 
    console.log('DONE')
}

Even though I have returned the promise inside the first method, the calling function still receives undefined. I cannot understand what is wrong there.

As you can see, I just log the data to return to the console inside the second function just before returning. Data is there.

Can someone please help me here. Thank You..!

vigamage
  • 1,975
  • 7
  • 48
  • 74

2 Answers2

1

You'll want to remove the return new Promise(async (resolve, reject) => { line and just make getCodesOfOneMerchant itself async:

async getCodesOfOneMerchant(merchantDataEntry: MerchantData) { /*
^^^^^ */
  const codesOfMerchant = [];
  for (const value of merchantDataEntry.qrPayloadList) {
    this.qrvalue = value.qrPayload;

    while (!document.querySelector(".qrcode img")) {
      await new Promise(r => setTimeout(r, 500));
      console.log("waiting for qr");
    }
    console.log("QR element is available");
    const qrEle = document.getElementById('qrcode');
    let imgBase64Data = this.getBase64Image(qrEle.firstChild.firstChild);
    console.log('Base64 = ' + imgBase64Data);

    const userQr: UserQr = new UserQr();
    userQr.name = merchantDataEntry.serviceName + "-" + value.branch + "-" + value.mobile;
    userQr.qr = imgBase64Data;

    codesOfMerchant.push(userQr);
  }
  return codesOfMerchant;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • let me have a look. However, my current implementation started working after adding what i need to resolve inside the resolve constructor. BTW, I think this solution does not pass an async function as a executor to promise which you mention as an anti pattern in a comment :) isn't it? – vigamage Aug 11 '20 at 03:39
  • @vigamage Yes, dropping that line fixes the problem – Bergi Aug 11 '20 at 08:13
-1

In the callee function in the below code

const promises = filteredData.map(async (value) => {
  const qrCodesOfMerchant = await this.getCodesOfOneMerchant(value);
  return qrCodesOfMerchant;
});

you are already awaiting for the response of the method getCodesOfOneMerchant, which will resolve the promise there itself.

Instead, you just need to dump all the promises in the promises array and await all of them once using Promise.all(promises)

const promises = filteredData.map(value => this.getCodesOfOneMerchant(value))
const qrCodesOfAll = await Promise.all(promises);

This will give qrCodesOfAll as an array of resolved promises

Also, the executor function is returning a promise but the promise is never resolved. The returned values from the promise i.e codesOfMerchant will never be received by the callee. You will need to resolve that promise by using

resolve(codesOfMerchant)

which will now return the value of codesOfMerchant to the callee

Aayush Mall
  • 963
  • 8
  • 20
  • 1
    Please check for the updated answer, you did not resolved the promise in the executor function. A promise needs to be resolved to return the data. – Aayush Mall Aug 08 '20 at 09:30
  • Well adding `codesOfMerchant` inside resolve did the trick. However, i didnt make the changes you have suggested before resolve thing. – vigamage Aug 11 '20 at 03:33