Qasim Mohammed
Qasim Mohammed

Reputation: 9

Async wait is not working when calling a function

var value = await this.upload();
if (value == true) {
  this.item.photos = this.uploaded;
  this.item.price = null;
  this.item.qty = null;
  this.dataSrv.addItem(this.item)
    .then(() => {
      this.dataSrv.stopLoading();
      this.dataSrv.toast('Item Added Successfully');
      this.item = {} as Item;
      this.pictures = ['', '', '', ''];
      this.uploaded = [];
      this.photos = ['', '', '', ''];
    })
    .catch(err => {
      this.dataSrv.stopLoading();
      this.dataSrv.toast('Error While Adding Item. Try Again Later');
      console.log(err);
    });
}

In the above code I am calling upload function to upload picture to Google storage and I am waiting so I can add the image links to uploaded array which will save it to this.item.photos but It does not wait and it directly execute the true condition.

async upload(image?) {
  var counter = 0;
  this.pictures.forEach(i => {
    if (i != '') {
      let temp: string = (i) as string;
      temp = temp.replace("data:image/jpg;base64, ", '');
      temp = temp.replace("data:image/jpg;base64,", '');
      temp = temp.replace('must use [property]=binding:', '');
      temp = temp.replace('SafeValue', '');
      temp = temp.replace('(see https://g.co/ng/security#xss)', '');
      const randomId = Math.random().toString(36) + Math.random().toString(36) + Math.random().toString(36) + Math.random().toString(36);
      const uploadTask = this.storage.ref('items/').child(randomId).putString(temp, 'base64', {
        contentType: 'image/png'
      });
      uploadTask
        .then(response => {
          console.log("uploaded");
          console.log(response);
          this.storage.ref('items/' + randomId).getDownloadURL().subscribe(url => {
            this.uploaded.push(url);
            counter++;
          });
        })
        .catch(err => {
          console.log('not uploaded');
        });
    }
  });
  if (counter != this.uploaded.length) {
    return false;
  } else {
    return true;
  }
}

I have tried to do return type of Promise in the upload function but nothing changed I have also tried to do the then after the function call but the same issue happen

Note that pictures array contains base64 image

Upvotes: 1

Views: 230

Answers (1)

Nemanja Miljković
Nemanja Miljković

Reputation: 997

async functions will not block by themselves. The issue is that the forEach is called synchronously, but it contains code which will run asynchrnously.

A common pattern for doing this:

async upload(image) {
  // use .map instead of .forEach
  // from the callback function we return a Promise, so the result would be
  // an array of promises
  const promises = this.pictures.map(i => {
    // your logic here
    // you must return the promise
    return uploadTask
        .then(response => { /* ... */ })
        .catch(() => { /* ... */ });
  })

  // Wait for all promises to be resolved.
  // Note for the future: Promise.all will reject if at least 1 promise rejects.
  // Your code seems to handle this case and converts a failed Promise into a success inside of `.catch` above.
  await Promise.all(promises);

  // here, the counter should be correct
}

Upvotes: 2

Related Questions