0

I have the following code, which works:

interface MyImages {
  apple: HTMLImageElement,
  banana: HTMLImageElement,
  carrot: HTMLImageElement
}

async function fetchImages(): Promise<MyImages> {
  const images = await Promise.all([
    asyncImageLoad("/images/apple.png"),
    asyncImageLoad("/images/banana.png"),
    asyncImageLoad("/images/carrot.png")
  ]);

  return {
    apple: images[0],
    banana: images[1],
    carrot: images[2]
  };
}

However, it's a bit verbose. Also, it's error-prone, because you have to match up the array indexes with the proper element.

I would much rather just do this:

async function fetchImages(): Promise<MyImages> {
  return {
    apple: await asyncImageLoad("/images/apple.png"),
    banana: await asyncImageLoad("/images/banana.png"),
    carrot: await asyncImageLoad("/images/carrot.png")
  };
}

This is much more concise, less error-prone, but unfortunately it synchronously queries each image.

That is, instead of sending all requests at once, this one first queries for the apple, awaits for it to return, then queries for the banana, awaits for it to return, and then finally queries the carrot image.

Is there any way to have the ergonomics of the latter with the performance of the former?

Ryan Peschel
  • 11,087
  • 19
  • 74
  • 136
  • 3
    `const [apple, banana, carrot] = await Promise.all(...); return { apple, banana, carrot }`? Or you could start from the array `["apple", "banana", "carrot"]` and generate everything from that via e.g. `Object.fromEntries`. – jonrsharpe Feb 12 '23 at 11:48
  • @jonrsharpe Oh thanks your first suggestion is pretty good! I'm not sure what you mean exactly with `Object.fromEntries` so I'll have to experiment a bit I think – Ryan Peschel Feb 12 '23 at 11:56

1 Answers1

2

This alternative implementation of your function is based on @jonrsharpe's suggestion about using Object.fromEntries.

async function fetchImages(): Promise<MyImages> {
  const sources = ["apple", "banana", "carrot"];
  const images = await Promise.all(
    sources.map(async source => {
      const image = await asyncImageLoad(`/images/${source}.png`);
      return [source, image];
    })
  );
  return Object.fromEntries(images);
}
Ryan Peschel
  • 11,087
  • 19
  • 74
  • 136
Jonas V
  • 668
  • 2
  • 5
  • 20
  • 1
    I'm having trouble getting this working. Did you mean to `await` the `asyncImageLoad` function? If so, I think there needs to be an `await` keyword before `source`. Otherwise, `await` shouldn't be before `asyncImageLoad`. – Ryan Peschel Feb 12 '23 at 12:17