Can await and then be mixed in one implementation?

2019-07-25 15:24发布

问题:

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.

回答1:

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 respnse = 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;
  }
},