简体   繁体   中英

Promise inside promise consistently

I have been tormented with this problem for 2 days, but did not dare to ask this question. I read a lot of documentation about promises and asynchronous functions. Perhaps the answer to this question will be useful to other users.

I want to call the details of a detail item in a list of items.

The list array looks like this:

[
  {
    "id": 1,
    "name: "A",
  },
  {
    "id": 2,
    "name: "B",
  },
  ...
]

The one data I want to call inside list array:

{
  "id": 1,
  "url: "aaa",
  "props": ["a", "a", "a"]
}

react-admin Promises:

const list = dataProvider.getList(resource, params);
const one = (id: number) => dataProvider.getOne(resource, { id })

dataProvider return a Promise for an object with a data property.

I wrote a function that returns data in parallel:

const data = async () => {
  const list = await dataProvider.getList(resource, params);
  const one = (id: number) => dataProvider.getOne(resource, { id });

  list.data = await Promise.all(
    list.data.map(async (item) => {
      const itemOne = await one(item.id);

      return {
        ...item,
        custom: {
          test: itemOne.data.url,
        },
      };
    })
  );

  return list;
};

console.log(data())

Now I'm trying to use a reduce instead of a map .

Please help me find the right solution or direction.

But in this case, the promises are processed all at once, and not sequentially, so they make incredibly long page load time.

Now I'm trying to use a reduce instead of a map.

It's unlikely that doing them in series (one after another) instead of in parallel (as you are now) would make anything faster; it's much more likely that it would make the page load take longer . But if you want to do those operations in series (one after another) rather than in parallel (all happening concurrently), reduce is over-complicated for that (and nearly everything else). Just use a for-of loop. I've included an example at the end of the answer.

I haven't used react-admin, but whenever getting a bunch of things from an API one-by-one is slow, I look to see if I can ask for them all at once instead. Looking at the documentation , you can use getMany instead of getOne . Something like this:

const data = async () => {
  // Get the list
  const list = await dataProvider.getList(resource, params);

  // Get the items
  const items = await dataProvider.getMany(resource, { ids: list.data.map(({id}) => id) });
  // Extracting each `id` from the item to create the array −−−−−−−−−^^^^^^^^^^^^^^^^^

  // Add those to the list items
  list.data = list.data.map((item, index) => {
    return {
      ...item,
      custom: {
        test: items.data[index].url,
      },
    };
  });

  return list;
};

Note that that assumes that the data that comes back from getMany is in the same order as the ids array. The documentation seems to suggest that in the examples, but sadly doesn't actually say it.

If it turns out that it doesn't give them to you in the order you asked for them, you'll probably want to make a map keyed by id :

const data = async () => {
  // Get the list
  const list = await dataProvider.getList(resource, params);

  // Get the items
  const items = await dataProvider.getMany(resource, { ids: list.data.map(({id}) => id) });
  // Extracting each `id` from the item to create the array −−−−−−−−−^^^^^^^^^^^^^^^^^

  // Build the map of those items keyed by `id`
  const map = new Map(items.data.map(item => [item.id, item]));

  // Add those to the list items
  list.data = list.data.map((item, index) => {
    return {
      ...item,
      custom: {
        test: map.get(item.id).url,
      },
    };
  });

  return list;
};

Here's that for-of loop to do the work in series, but again, I think it's likely to make the problem worse , not better.

const data = async () => {
  const list = await dataProvider.getList(resource, params);
  const data = [];
  for (const item of list.data) {
      const itemOne = await dataProvider.getOne(resource, { id: item.id })
      data.push({
        ...item,
        custom: {
          test: itemOne.data.url,
        },
      });
  }
  list.data = data;
  return list;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM