How to get around async promise executor

Viewed 27

I'm fetching images from my app through js but eslint is warning about using async promise executors. I know that in other cases like this, you could just remove the promise all-together, but not sure if that's applicable here.

Here is the code in question:

async fn() {
    let urls = _.map($('#img-container img'), (img) => $(img).attr('src'));

    urls = await Promise.all(urls.map((url) => new Promise(async (res) => { // FIXME - async promise executor
        const blob = await (await fetch(url)).blob();
        const reader = new FileReader();
        reader.readAsDataURL(blob);
        reader.onload = res;
    })));

    urls = urls.map((u) => u.target.result);
    return Buffer.from(pako.deflate(JSON.stringify(urls))).toString('base64');
}

How could I restructure this to get rid of this pattern? Or should I just dismiss the warning?

1 Answers

ESlint is complaining because there shouldn't be a need for an explicit Promise's executor to be async, because it generally means you're doing something wrong (mixing things that are already promisesque with building explicit promises).

You'll have a better time altogether (and ESlint won't complain either) if you refactor things so the callback-style FileReader API is wrapped in its own function that returns a promise (and that executor doesn't need to be async).

function blobToDataURL(blob) {
  return new Promise((res) => {
    const reader = new FileReader();
    reader.readAsDataURL(blob);
    reader.onload = res;
  });
}

async function x() {
  let urls = _.map($("#img-container img"), (img) => $(img).attr("src"));

  const dataUrls = await Promise.all(
    urls.map(async (url) => {
      const blob = await fetch(url).blob();
      return blobToDataURL(blob);
    }),
  );
}
Related