3

I'm looping through some data and fetching individual navigation items.

If I console.log(navItems) before the return in the getNavItems function, it logs everything I expect.

However, if I log footerData before my return inside getFooterData, I'm returned with an unresolved promise inside my items

[
  { heading: 'Heading 1', items: Promise { <pending> } },
  { heading: 'Heading 2', items: Promise { <pending> } },
  { heading: 'Heading 3', items: Promise { <pending> } },
]

What I'm expecting is something more like:

[
  { heading: 'Heading 1', items: [ {data: 1}, {data: 2}, {data: 3} ] },
]
const getNavitems = async (navItemList) => {
  const navItemIds = navItemList.map(({ sys: { id } }) => id);

  const navItemData = await Promise.all(
    navItemIds.map((id) => client.getEntry(id))
  );

  const navItems = navItemData.map((item) => item.fields);

  return navItems;
};

const getFooterData = async () => {
  const footerDataCollection = await client.getEntry('abcxyz123');

  const footerData = Object.entries(footerDataCollection.fields.sections).map(
    (item) => {
      return {
        heading: item[1].fields.heading,
        items: (() => getNavitems(item[1].fields.item_list))()
      };
    }
  );

  return footerData;
};

Any help would be great as I've been banging my head on this for hours now!

PHP Guru
  • 1,301
  • 11
  • 20
Nick
  • 2,261
  • 5
  • 33
  • 65
  • similar to how you collected an array of promises and waited for them to be done for `navItemData`, so too do you have to wait on the promises in items. – Kevin B Dec 16 '20 at 22:49
  • Have you tried `(await client).getEntry('abcxyz123');`? Or `(await (await client).json()).getEntry('abcxyz123');` – Rojo Dec 16 '20 at 22:50
  • Could try `return await Promise.all(footerData);` – Nick Dec 16 '20 at 22:50
  • @KevinB Where do I need to do this, sorry! I'm not 100% sure I follow! – Nick Dec 16 '20 at 22:53
  • @Rojo / Nick - No luck - Thank you though! – Nick Dec 16 '20 at 22:54
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Jared Smith Dec 16 '20 at 23:03
  • What does your `navItems` resolved Object look like? – StackSlave Dec 16 '20 at 23:36
  • 1
    @StackSlave navItems is an array of objects that just has 2 strings. `[ { a: 'hello', b: 'world' } ]` – Nick Dec 17 '20 at 00:05

3 Answers3

1

A solution that uses a loop. (Array.prototype.map is tricky with await)

I haven't tested this, since I have no way to do it.

const getNavitems = async (navItemList) => {
  const navItemIds = navItemList.map(({ sys: { id } }) => id);

  const navItemData = await Promise.all(
    navItemIds.map((id) => client.getEntry(id))
  );

  const navItems = navItemData.map((item) => item.fields);

  return navItems;
};

const getFooterData = async () => {
  const footerDataCollection = await client.getEntry('abcxyz123');

  const footerData = Object.entries(footerDataCollection.fields.sections);

  const items = await Promise.all(footerData.map(item => getNavitems(item[1].fields.item_list)));

  for (let i = footerData.length; i--;) {
      footerData[i] = {
          heading: footerData[i][1].fields.heading,
          items: items[i]
      }
  }

  return footerData;
};
robe007
  • 3,523
  • 4
  • 33
  • 59
PHP Guru
  • 1,301
  • 11
  • 20
  • This should throw an error due to using `await` in a non-async function. Making the map callback async will require additional code to get the intended array from it. – Kevin B Dec 16 '20 at 23:18
  • I noticed that too so I rewrote it so that it uses a loop – PHP Guru Dec 16 '20 at 23:33
0

Maybe instead items: (() => getNavitems(item[1].fields.item_list))() try items: await getNavitems(item[1].fields.item_list). What the anonymous function exactly is for there?

const footerData = await Promise.all(Object.entries(footerDataCollection.fields.sections).map(
    async (item) => {
      return {
        heading: item[1].fields.heading,
        items: await getNavitems(item[1].fields.item_list)
      };
    }
  ));
vicodin
  • 91
  • 8
  • `getNavitems` is already `async`. OP just needs `items: ()=>getNavitems(item[1].fields.item_list)`, but that seems to not be the issue. – StackSlave Dec 16 '20 at 23:34
  • Would using await inside of Array.prototype.map like this cause all of the promises to be resolved in sequence one after the next? Or is that optimized away by the compiler such that promises are resolved in parallel? – PHP Guru Dec 17 '20 at 16:30
  • Will execute in sequence, but the map will not wait for result, so the result of the executed functions may be ready in different order (like in parallel). `Promise.all([...])` wait until all functions done. – vicodin Dec 17 '20 at 19:01
-1

In items: (() => getNavitems(item[1].fields.item_list))(), you need to insert another await.

items: (async () => await getNavitems(item[1].fields.item_list))()

getNavItems is an async function. Therefore, you must use await to get the return value.

Rojo
  • 2,749
  • 1
  • 13
  • 34