如何更改订阅顺序?

时间:2019-05-28 17:28:45

标签: angular rxjs

如何更改执行顺序?我有一个数组this.friend,我需要使用这个数组,但是需要填充数据

this.listUserService.getUsers().subscribe(
    async (data: any) => {
           this.listUsers = data;
           await data.forEach((current: any) => {
                 if (current.name === userSession) {
                      this.user = current;
                      this.friendsService.getFriends(this.user.id).subscribe(response => {
                                console.log('last', response);//this runs second
                                this.friends = response;
                            });
                        }
                    });
                    console.log('friends', this.friends); //friend is clear, 
this runs first
                    this.listUsers = this.listUsers.filter(user => !this.friends.some(relationship => relationship[0].friend.id !== user.id));
                }
            );

控制台消息以相反的顺序显示,一旦装满,我要如何更改顺序

3 个答案:

答案 0 :(得分:2)

没有必要将诺言与可观察变量混合。另外,将subscribe()方法彼此嵌套也是一个好主意。我建议您使用RxJS运算符处理上述操作。

首先,我们使用mergeMap将服务的getUsers()方法中的可观察值映射到内部可观察值。

然后,我们使用forkJoin等待Array.forEach()循环完成,然后返回所有可观察值。由于您似乎熟悉JavaScript中Promises的用法,因此它实际上类似于Promise.all

最后但并非最不重要的一点,我们在listUsers块中处理subscribe()的过滤。这将确保您的异步代码得到正确处理。

this.listUserService.getUsers().pipe(
  mergeMap(data => {
    this.listUsers = data;
    const observablesList = [];
    data.forEach((current: any) => {
      if (current.name === userSession) {
        observablesList.push(this.friendsService.getFriends(current.id));
      }
    });
    return forkJoin(observablesList);
  })
).subscribe(response => {
  // console.log(response) will give you the returned values from the looped getFriends()
  // handle the rest here

});

答案 1 :(得分:1)

您可以尝试使用switchMapmaptap之类的RxJS运算符来控制可观察对象的流,包括执行诸如设置类属性之类的副作用。

此答案假设在forEach()中只有一个来自if (current.name === userSession) {的当前用户,随后this.friendsService.getFriends(user.id)仅执行一次。

import { map, switchMap, tap } from 'rxjs/operators'; // need to import operators

// ...

this.listUserService.getUsers().pipe(
  tap(users => this.listUsers = users), // side effect to set this.listUsers
  map(users => users.find(user => user.name === userSession)), // find current user
  switchMap(user => this.friendsService.getFriends(user.id)), // get friends of current user
  tap(friends => this.friends = friends), // side effect to set this.friends
  map(friends => this.listUsers.filter(user => this.friends.some(relationship => relationship[0].friend.id !== user.id)))
).subscribe(listUsers => {
  this.listUsers = listUsers;
});

您绝对应该查看RxJS文档,以获取更多信息和各种运算符的示例。另外,如果找不到当前用户或任何服务/ api调用失败,您肯定需要改进错误处理。

希望有帮助!

答案 2 :(得分:1)

那是因为您以错误的方式使用RxJS流。您首先设置流,所以其他所有console.log将首先运行。 Rx流本身是异步的,因此您不需要async await。另一个console.log将在实际调用流并接收数据时运行。

RxJS方法是在Rx流中.pipe() filter()

与其说是Angular问题,不如说是与RxJS有关。这是一个看起来像的例子:

   this.listUserService
  .getUsers()
  .pipe(
    tap(listUserData => {
      this.listUsers = listUserData;
    }),
    switchMap(data => {
      return this.friendsService.getFriends(data.id).pipe(
        tap(friends => {
          this.friends = friends;
        })
      );
    })
  )
  .subscribe();

switchMap切换到另一个可观察的水下,因此您不需要两个订阅。这被认为是好习惯!

我强烈建议您花一些时间学习RxJS,它将使您在Angular中的体验更加有趣和高效!

如果您愿意,我可以帮助您!