Cleaner Promise.all syntax?

Viewed 532

I am fairly new to Node.JS, and I really hate the syntax of Promise.all returning an array.

eg.

const requiredData = await Promise.all([
        getFirst(city),
        getSecond(hubIds),
        getThird(city, customerCategoryKey),
        getFourth(request)
    ])

const firstData = requiredData[0];
const secondData = requiredData[1];
const thirdData = requiredData[2];
const fourthData = requiredData[3];

I need to individually fetch them in separate lines of code. Isn't there a way like

const {
firstData,
secondData,
thirdData,
fourthData
} = await Promise.all([
        getFirst(city),
        getSecond(hubIds),
        getThird(city, customerCategoryKey),
        getFourth(request)
    ])

Basically, I'd really like if there is a cleaner way than the first code snippet.

TIA!

2 Answers

As mentioned in the comments you can use Array destructor instead of using Object destructor:

(async () => {
  const promise1 = Promise.resolve(3);
  const promise2 = 42;
  const promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, "foo");
  });

  // get all elements as variables
  const [p1, p2, p3] = await Promise.all([promise1, promise2, promise3]);

  console.log(p1, p2, p3);
})();

In case it's not obvious, if you're okay running the promises in serial order, you can await them inline -

const main = async () =>
{ const a = await mock("one")
  const b = await mock("two")
  const c = await mock("three")
  const d = await mock("four")

  console.log(a, b, c, d)
}

// test funcs
const rand = n =>
  Math.floor(Math.random() * n)

const mock = (x) =>
  new Promise(r => setTimeout(r, rand(1000), x))

// run
console.log("loading...")
main().catch(console.error)

// loading...
// one two three four

If you want to run the promises in parallel but retrieve assign the values by name, we could fromDescriptor which does the wiring for us -

const fromDescriptor = (desc = {}) =>
  Promise.all( 
    Object
      .entries(desc)
      .map(([ k, px ]) => px.then(x => [ k, x ]))
  )
  .then(Object.fromEntries)

const main = async () =>
{ const init =            
    { a: mock("one")
    , b: mock("two")
    , c: mock("three")
    , d: mock("four")
    }
  
  const { a, b, c, d } =
    await fromDescriptor(init)

  console.log(a, b, c, d)
}

// test funcs
const rand = n =>
  Math.floor(Math.random() * n)

const mock = (x) =>
  new Promise(r => setTimeout(r, rand(1000), x))

// run
console.log("loading...")
main().catch(console.error)

// loading...
// one two three four

Related