简体   繁体   English

是否有可能在 angular 中等待订阅?

[英]Is there a possibility to await a subscription in angular?

I would like to show a list of posts like this: Post List我想显示这样的帖子列表:帖子列表

To show which post is favorized by a user I need data from two different collections out of my mongodb database.为了显示用户喜欢哪个帖子,我需要来自我的 mongodb 数据库中两个不同 collections 的数据。 Currently the ngOnInit of my post-list.component.ts file looks like this:目前我的 post-list.component.ts 文件的 ngOnInit 如下所示:

 ngOnInit() { this.isLoading = true; this.postsService.getPosts(this.postsPerPage, this.currentPage); this.favoritesService.getFavorites(this.postsPerPage, this.currentPage); this.userId = this.authService.getUserId(); this.postsSub = this.postsService.getPostUpdateListener().subscribe((postData: { posts: Post[]; postCount: number }) => { this.totalPosts = postData.postCount; this.posts = postData.posts; console.log("Posts fetched successful;"); }). this.favoritesSub = this.favoritesService.getFavoriteUpdateListener():subscribe( (favoriteData: { favorites; Favorite[]: postCount. number }) => { this;isLoading = false. this.favorites = favoriteData;favorites. this;fetchFavorites(). console;log("Favorites fetched successful;"). } ). this.userIsAuthenticated = this;authService.getIsAuth(). this.authStatusSub = this.authService.getAuthStatusListener();subscribe((isAuthenticated) => { this.userIsAuthenticated = isAuthenticated. this.userId = this;authService;getUserId(); }); }
My post list is only shown correctly if the post data arrives first. 只有当帖子数据先到达时,我的帖子列表才会正确显示。 Due the asynchrony of subscriptions I can't control which data arrives first. 由于订阅的异步性,我无法控制哪些数据先到达。 What I already tried is to use the completed function of subscribe but it was never executed. 我已经尝试过的是使用完成的 function 订阅,但从未执行过。 Another approach was to outsource the favorites part into a own function and execute it after the posts are fetched. 另一种方法是将收藏夹部分外包给自己的 function 并在获取帖子后执行它。 Both approches ended up in a endless loading circle. 两种方法都以无休止的加载循环结束。

Is there any possibility to first await the post data to arrive?是否有可能首先等待发布数据到达?

You have several options to achieve your wanted behavior.您有多种选择来实现您想要的行为。

Option 1:选项1:

You can use the RxJS operator switchMap which becomes executed as soon as the subscription emits and returns a new Observable.您可以使用 RxJS 运算符switchMap ,它会在订阅发出并返回新的 Observable 时立即执行。 See here for more infos about switchMap ;)有关switchMap的更多信息,请参见此处;)

I'm using your calls getPostUpdateListener and getFavoriteUpdateListener as example, so it would look something like this:我使用你的调用getPostUpdateListenergetFavoriteUpdateListener作为例子,所以它看起来像这样:

...

this.postsSub = this.postsService
  .getPostUpdateListener()
  .pipe(
    switchMap((postData: { posts: Post[]; postCount: number }) => {
      this.totalPosts = postData.postCount;
      this.posts = postData.posts;
      console.log("Posts fetched successful!");

      return this.favoritesService.getFavoriteUpdateListener();
    })
  )
  .subscribe((favoriteData: { favorites: Favorite[]; postCount: number }) => {
    this.isLoading = false;
    this.favorites = favoriteData.favorites;
    this.fetchFavorites();
    console.log("Favorites fetched successful!");
  });

...

Option 2:选项 2:

You can promisify your Observable with firstValueFrom or lastValueFrom and then you can wait for it's execution, eg with async/await.您可以使用firstValueFromlastValueFrom承诺您的 Observable,然后您可以等待它的执行,例如使用 async/await。 See here for more information;)有关更多信息,请参见此处;)

This would look like following:这将如下所示:

async ngOnInit() {
  ...

  const postData: { posts: Post[]; postCount: number } = await firstValueFrom(this.postsService.getPostUpdateListener());
  
  this.totalPosts = postData.postCount;
  this.posts = postData.posts;
  console.log("Posts fetched successful!");

  const favoriteData: { favorites: Favorite[]; postCount: number } = await firstValueFrom(this.favoritesService.getFavoriteUpdateListener());
  this.isLoading = false;
  this.favorites = favoriteData.favorites;
  this.fetchFavorites();
  console.log("Favorites fetched successful!");

  ...
}

Since Angular is working a lot in the reactive way I'd go with option 1;)由于 Angular 以被动方式工作很多,所以我会选择 go 和选项 1;)

For clean code you can utilize rxjs forkJoin operator for the exact purpose.对于干净的代码,您可以使用 rxjs forkJoin运算符来达到确切目的。 Basically what you have is two observables getting subscribed on component initialization.基本上你所拥有的是两个在组件初始化时订阅的 observables。 forkJoin works on joining multiple observable streams, or for the better understanding think about how Promise.all would await all possible Promises . forkJoin致力于加入多个可观察的流,或者为了更好地理解考虑Promise.all将如何等待所有可能的Promises

Another options to not use subscribe and user .toPromise() and await.另一个不使用subscribe和 user .toPromise()和 await 的选项。 for reference check out this post供参考查看这篇文章

It will be better in your case to use combineLatest(RxJS v6) or combineLatestWith(RxJs v7.4).在您的情况下,使用 combineLatest(RxJS v6) 或 combineLatestWith(RxJs v7.4) 会更好。 combineLatest operator will emit every time any of the source Observables emit after they've emitted at least once. combineLatest 运算符将在任何源 Observable 至少发出一次后发出。 As your services do not depend on each other then it will be better to use combineLatest in your case.由于您的服务不相互依赖,因此在您的情况下使用 combineLatest 会更好。

    this.postsSub = this.postsService.getPosts(this.postsPerPage, this.currentPage);
    this.favoritesSub  = this.favoritesService.getFavorites(this.postsPerPage, this.currentPage);

combineLatest([this.postsSub, this.favoritesSub]).pipe(
            map(([postData, favoriteData]) => {
               this.totalPosts = postData.postCount;
               this.posts = postData.posts;
               console.log("Posts fetched successful!");
               this.isLoading = false;
               this.favorites = favoriteData.favorites;
               this.fetchFavorites();
               console.log("Favorites fetched successful!");
            })).subscribe();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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