Can await and then be mixed in one implementation? [duplicate]
Asked Answered
O

1

10

I'm wondering if await and .then can be used in the same async function? Here is my function:

uploadImageToImgur: async function (file) {
return new Promise(function(resolve, reject) {
  const url = 'https://api.imgur.com/3/image',
  reader  = new FileReader();

  if (file) {
    reader.readAsDataURL(file);
  }

  reader.onloadend = async function () {
    let { result } = reader;

    try {
      const request = await fetch(url, {
        method: 'POST',
        headers: {
          "Authorization": 'my auth',
        },
        body: result.replace(/^data:image\/(png|jpg|jpeg|gif);base64,/, "")
      })
      .then((response) => {
        response.json()
        .then(data => {
          resolve(data.data.link)
        })
      });
    } catch (e) {
      reject(e);
    }
  }
});
},

Then I call this function in another one where I save the object to indexedDb with the link i've got from the imgur API.

this.uploadImageToImgur(image)
  .then((image) => {
    let db = this.dbOpen.result,
        tx = db.transaction('EventsStore', 'readwrite'),
        store = tx.objectStore('EventsStore');

    event = store.put({ title, location, description, summary, date, time, image });
    //rest of the code
  });

Why did I choose this approach? Because when I used only await keyword (without promise constructor), data was adding to the db before promise was resolved ;/ What was not what I wanted (probably I made a mistake somewhere.. idk).

My question is if the code above is the correct way to do that (it works as intended) or should I refactor it? If so, please tell me how. This question is rather informative for me than related with a specific problem. Thank You.

Ocana answered 7/2, 2019 at 13:40 Comment(0)
G
19

Yes, you can use mix await and then syntax - they both work on promises - but you shouldn't do so in the same function.

But that's not the main issue in your code. The problem is the use of the Promise constructor antipattern in the uploadImageToImgur function. Do not use async functions as callbacks. Do not create promises in then callbacks without returning them - rejections of response.json() are not caught by your code.

Yes, you will need the Promise constructor to promisify the reader, but that's it. Factor it out inside its own function so that you don't lead yourself into temptation. That if (file) condition inside the executor led to your promise being never resolved in some cases!

Cleaned up:

function readDataUrl(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = function() {
      resolve(this.result);
    };
    reader.onerror = reader.onabort = reject; // don't forget this!
    reader.readAsDataURL(file);
  });
}

uploadImageToImgur: async function(file) {
  const url = 'https://api.imgur.com/3/image',
  if (file) {
    const result = await readDataUrl(file);
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        "Authorization": 'my auth',
      },
      body: result.replace(/^data:image\/(png|jpg|jpeg|gif);base64,/, "")
    });
    const data = await response.json();
    return data.data.link;
  }
}
Geez answered 7/2, 2019 at 14:8 Comment(2)
Is it convention to leave reject to its default implementation?Announcer
@Slaiyer I don't know about "convention", but yes, if it is possible (and useful) then I would recommend to avoid wrapping resolve and reject in an unnecessary extra function. In this case, I expect the onerror callback to be called with the error as the argument, so it made sense to me. If you want to reject with a custom error/message, sure, go ahead with a function that rejects with that.Geez

© 2022 - 2024 — McMap. All rights reserved.