【问题标题】:forEach loop with async code?带有异步代码的 forEach 循环?
【发布时间】:2018-03-06 06:35:06
【问题描述】:

我正在使用不同的参数进行 3 次函数调用:

this.getContributorProperties('followers_url', 'contributorFollowers');
this.getContributorProperties('gists_url', 'contributorGists');
this.getContributorProperties('repos_url', 'contributorRepositories');

这个函数看起来像这样:

async getContributorProperties(propertyUrl, propertyName) {
    const contributors = await this.addLinkToContributor();
    for (let i = 0; i < 10; i += 1) {
      axios.get(`${contributors[i][propertyUrl]}?per_page=100&${API_KEY}`).then((res) => {
        contributors[i][propertyName] = res.data.length;
      });
    }
    return contributors;
}

它遍历一组贡献者(对象类型)并为每个贡献者进行 API 调用。我需要为它们中的每一个进行 3 次 API 调用,因此一开始就进行了 3 次调用。 为了干燥我的代码,我想像这样创建一个 forEach 循环:

[
      ['followers_url', 'contributorFollowers'],
      ['gists_url', 'contributorGists'],
      ['repos_url', 'contributorRepositories'],
    ].forEach(this.getContributorProperties);

forEach 循环位于componentDidMount() 当我打 3 个电话时,它工作正常。但是当我做 forEach 时,我得到一个错误:

Uncaught (in promise) TypeError: Cannot read property 'addLinkToContributor' of undefined

如何让它发挥作用?

奖励:我如何将这些键值对分配给每个对象?

【问题讨论】:

标签: javascript reactjs foreach async-await frontend


【解决方案1】:

请参阅How to access the correct this inside a callback? 和/或How does the "this" keyword work?,了解您收到该特定错误消息的原因。

但从根本上讲,无论如何,您都不想将该函数传递给forEach,因为forEach 不会传递它想要的函数。

相反,只需使用箭头函数:

[
  ['followers_url', 'contributorFollowers'],
  ['gists_url', 'contributorGists'],
  ['repos_url', 'contributorRepositories'],
].forEach(pair => this.getContributorProperties(pair[0], pair[1]).catch(err => {/*...handle error...*/});

注意错误处理;我们不想要未经处理的拒绝,forEach 不会做任何事情来将它们传播给调用者。


不过,不将返回值用于任何事情似乎很奇怪。也许mapPromise.all

const results = await Promise.all([
  ['followers_url', 'contributorFollowers'],
  ['gists_url', 'contributorGists'],
  ['repos_url', 'contributorRepositories'],
].map(pair => this.getContributorProperties(pair[0], pair[1])));

...确保在调用者不处理错误的情况下处理错误。


请注意您的getContributorProperties 函数中有两个错误:

  1. 它不会等待axios.get 完成后返回(async 函数不会自动-await 承诺,你必须明确)

  2. 它不处理对axios.get返回的承诺的拒绝

我也很好奇重复调用this.addLinkToContributor 三次是否正确,第二次是否会浪费。

在您提出的评论中:

Results 是 3 个相同对象(贡献者)的数组,每个数组只更改了一个属性。因此,一个数组的贡献者有要点,另一个有追随者等。我现在是以某种方式将它们连接起来还是在getContributorProperties 函数中这样做更好?

那是我的直觉。比如:

async getContributorProperties(properties) {
    const contributors = await this.addLinkToContributor();
    return Promise.all(contributors.map(contributor =>
      Promise.all(properties.map(property =>
        axios.get(`${contributor[property.url]}?per_page=100&${API_KEY}`).then(res => {
          contributor[property.name] = res.data.length;
        })
      ));
    ));
}

这样称呼:

const results = await this.getContributorProperties([
  {url: 'followers_url', name: 'contributorFollowers'},
  {url: 'gists_url',     name: 'contributorGists'},
  {url: 'repos_url',     name: 'contributorRepositories'}
]);

(我们真的需要 await.all concept 这样上面就不会混淆它的隐喻......)

【讨论】:

  • Results 是 3 个相同对象(贡献者)的数组,每个数组只更改了一个属性。所以一个数组的贡献者有要点,另一个数组有追随者等。我现在是以某种方式连接它们还是在getContributorProperties函数中这样做更好?
  • @AdamMarczyk:我已经添加到答案中,解决了这个问题以及其他一些问题。
  • 这是否解决了第一个错误? ` 异步函数contributorsLoop() { for (let i = 0; i } } const res = awaitcontributorsLoop();返回资源; }`
  • @AdamMarczyk:这完全取决于&lt;loop here&gt; 中的内容。不过,我上面的解决方案确实做到了,同时保持一切并行。
  • 如果我不想映射所有贡献者怎么办?其中大约有 5k 个。我可以做些什么来只为 10 个贡献者进行 API 调用?
猜你喜欢
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多