【问题标题】:Promise inside promise consistently承诺中的承诺始终如一
【发布时间】:2020-06-07 15:45:33
【问题描述】:

我被这个问题折磨了2天,但不敢问这个问题。我阅读了很多关于 Promise 和异步函数的文档。也许这个问题的答案会对其他用户有用。

我想在项目列表中调用一个详细项目的详细信息。

list 数组如下所示:

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

我想在list数组中调用的one数据:

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

react-admin 承诺:

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

dataProvider 为具有data 属性的对象返回一个 Promise。

我写了一个并行返回数据的函数:

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())

现在我是 trying 来使用 reduce 而不是 map

请帮我找到正确的解决方案或方向。

【问题讨论】:

  • @T.J.克劳德,对不起,我无法理解地写了一个问题。已更正。我的意思是,当我执行 Promise.all 时,第一个页面加载需要很长时间,因为所有元素同时加载,我可能是错的。
  • 啊,谢谢你的澄清。 :-) 我已经更新了我的答案,我怀疑你是否想改为串联这些电话。
  • @T.J.克劳德,谢谢,你拯救了我的一些日子。看来我最初没有正确理解我的问题。
  • 我的荣幸!我刚刚注意到我已修复的答案中的代码示例中有一个错误,我忘记将getOne 更改为getMany...我现在已经修复了。

标签: javascript asynchronous promise async-await


【解决方案1】:

但在这种情况下,promise 是一次性处理的,而不是按顺序处理的,因此它们会导致页面加载时间非常长。

现在我正在尝试使用 reduce 而不是 map。

串联(一个接一个)而不是并行(就像你现在一样)不太可能使任何事情变得更快;它更有可能使页面加载花费更长。但是,如果您想以串行方式(一个接一个地)而不是并行地(所有操作同时发生)来执行这些操作,那么reduce 就会过于复杂(以及几乎所有其他操作)。只需使用for-of 循环。我在答案的末尾包含了一个示例。

我没有使用过 react-admin,但是每当从 API 中逐个获取一堆东西很慢时,我会看看是否可以一次全部请求它们。查看the documentation,您可以使用getMany 而不是getOne。像这样的:

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;
};

请注意,这假设从getMany 返回的数据与ids 数组的顺序相同。文档似乎在示例中暗示了这一点,但遗憾的是实际上并没有

如果事实证明它没有按照您要求的顺序将它们提供给您,您可能想要制作一个以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;
};

下面是 for-of 循环来按顺序完成工作,但同样,我认为这可能会使问题更糟,而不是更好。

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;
};

【讨论】:

    猜你喜欢
    • 2018-06-23
    • 2015-10-06
    • 2015-06-05
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多