【问题标题】:Add a Promise for each array item to a `Promise.all()`将每个数组项的 Promise 添加到 `Promise.all()`
【发布时间】:2021-01-23 07:01:02
【问题描述】:

我有以下代码,其中我遍历了一个包含名称的列表,并在这种情况下使用每个名称来获取相应的房子。这很好用,但我想将所有承诺包含在Promise.all() 中 - 如何将每个名称的承诺动态添加到Promise.all()?这里有什么好的做法?

list = [
  'Name1',
  'Name2',
  'Name3'
];

this.houses = new BehaviorSubject<any>([]);

const promises = this.greatHouses.map(name => {
  let house;
  return this.fetchHouse(name).then((result: any[]) => {
    house = result[0];
    return result[0];
  }).then((result: any) => {
    return this.fetchLord(result.currentLord);
  }).then((result: any) => {
    const currentLord = Characters.default.find(char => char.characterName === result.name);
    return [{...house, currentLord}];
  });
});

Promise.all(promises).then(values => {
  console.log(values);
});

fetchHouse(name: string) {
  return this.http.get(`${this.housesUrl}`, {
    params: {
      name
    }
  }).toPromise();
}

fetchLord(url: string) {
  return this.http.get(url).toPromise();
}

【问题讨论】:

  • 只收集你在数组中创建的承诺,然后调用Promise.all?最佳做法是为此使用map 而不是list 数组上的循环,但两者都可以。
  • 个人而言,我会使用 this.list.mapreturn this.fetchHouse .... etc 然后返回的数组可以与 Promise.all 一起使用
  • 顺便说一句,关于let house,还有更好的ways to access previous promise results in a .then() chain
  • 别忘了在最后加上.catch(console.error)。您更新的问题中的代码应该可以工作。
  • 你的单个 promise 也一样,只是你从来没有注意到它,因为你根本没有处理错误。

标签: javascript angular typescript promise rxjs


【解决方案1】:

根本不要使用 Promise。如果您使用的是 Angular 及其 HttpClient,请学习使用 Observables。

greatHouses = [
  'Name1',
  'Name2',
  'Name3'
];

// Construct and array of Observables that fetch your data
const houses$ = this.greatHouses.map(name => 
  this.fetchHouse(name).pipe(
    // map result to house
    map((result: any[]) => result[0]),
    // map house to an Observable that fetches the lord and return the required data
    switchMap((house: any) => this.fetchLord(house.currentLord).pipe(
      // map lord to house with currentLord
      map((lord: any) => {
        const currentLord = Characters.default.find(char => char.characterName === lord.name);
        return { ...house, currentLord };
      })
    ))
  )
);

// Combine an array of completing Observables with forkJoin to one Observable
forkJoin(houses$).subscribe(houses => console.log('houses', houses))

// Return Observables and handle errors with `catchError` directly where they occur.
fetchHouse(name: string) {
  return this.http.get(`${this.housesUrl}`, {
    params: {
      name
    }
  }).pipe(
    catchError(error => {
      console.error('fetchHouse failed', error);
      return of(null);
    })
  );
}

fetchLord(url: string) {
  return this.http.get(url).pipe(
    catchError(error => {
      console.error('fetchLord failed', error);
      return of(null);
    })
  );
}

【讨论】:

  • 这是 Observable 粉丝的解决方案。承诺更直接。 :-)
  • @Roamer-1888 您是否考虑直截了当很大程度上取决于您最了解的内容。因此,一个人可能认为 promise-way 简单,而另一个人认为 observable-way 简单。 OP 问题针​​对 Angular。 RxJS 是 Angular 的核心依赖,在整个 Angular 中大量使用。任何使用 Angular 的人都应该熟悉并熟悉 RxJS。在这种情况下,在遇到的每个 Observable 上使用 toPromise 并不是一个好习惯。 Observables 通常更灵活,因为它们可以通过多种方式与其他 Observables 和事件组合。
猜你喜欢
  • 1970-01-01
  • 2020-08-06
  • 2017-07-01
  • 2020-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
  • 2019-06-24
相关资源
最近更新 更多