简体   繁体   English

可观察的退订

[英]Observable unsubscribe

I have read that every component should unsubscribe to all subscriptions at the end in the 我已经读到,每个组件都应在末尾退订所有订阅。

ngOnDestroy()

for instance. 例如。 I have the following blog component: 我有以下博客组件:

import { Component, OnInit } from '@angular/core';
import { ISubscription } from "rxjs/Subscription";

import { CarouselConfig } from 'ngx-bootstrap/carousel';

import { BlogPost } from '../shared/blogPost';
import { BlogPostFactory } from '../shared/blogPost-factory';

import { DataService } from '../data.service';

@Component({
  selector: 'ca-blog',
  templateUrl: './blog.component.html',
  styleUrls: ['./blog.component.css'],
  providers: [{provide: CarouselConfig, useValue: {interval: 1500, noPause: true}}]
})
export class BlogComponent implements OnInit {
  private blogPosts: BlogPost[] = [];
  private heartsUp: string[] = [];
  private likesUp: string[] = [];
  private heartSub: ISubscription;
  private likeSub: ISubscription;

  constructor(private dataService: DataService) {
    window.onscroll = () => {
      let windowHeight = "innerHeight" in window ? window.innerHeight : document.documentElement.offsetHeight;
      let body = document.body;
      let html = document.documentElement;
      let docHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
      let windowBottom = windowHeight + window.pageYOffset;

      if(windowBottom >= docHeight) {
        let urlSearchParams = { last: this.blogPosts.length };

        this.dataService.getBlogPosts(urlSearchParams).subscribe( result => {
          for(let i=0; i<result.length; i++){
            this.blogPosts.push(BlogPostFactory.fromObject(result[i]));
          }
        });
      }
    };
  }

  ngOnInit() {
    this.dataService.getBlogPosts().subscribe( result => {
      for(let i=0; i<result.length; i++){
        this.blogPosts.push(BlogPostFactory.fromObject(result[i]));
      }
    });
  }

  incrementHearts(index) : void {
    let idIndex : number = this.heartsUp.indexOf(this.blogPosts[index].id);

    if(idIndex != -1){
      this.blogPosts[index].hearts--;

      this.heartsUp.splice(idIndex, 1);

    } else {
      this.blogPosts[index].hearts++;

      this.heartsUp.push(this.blogPosts[index].id);
    }

    this.heartSub = this.dataService.editBlogPost(this.blogPosts[index].id, { hearts: this.blogPosts[index].hearts }).subscribe();
  }

  incrementLikes(index) : void {
    let idIndex : number = this.likesUp.indexOf(this.blogPosts[index].id);

    if(idIndex != -1){
      this.blogPosts[index].likes--;

      this.likesUp.splice(idIndex, 1);

    } else {
      this.blogPosts[index].likes++;

      this.likesUp.push(this.blogPosts[index].id);
    }

    this.likeSub = this.dataService.editBlogPost(this.blogPosts[index].id, { likes: this.blogPosts[index].likes }).subscribe();
  }

  ngOnDestroy() {
//    this.likeSub.unsubscribe();
//    this.heartSub.unsubscribe();
  }
}

But when i uncomment the two lines in the ngOnDestroy() function then my site crashes. 但是,当我取消注释ngOnDestroy()函数中的两ngOnDestroy()我的网站崩溃了。 It says that heartSub and likeSub is undefined. 它说heartSublikeSub是未定义的。 The appropriate HTML file looks like this: 适当的HTML文件如下所示:

<div class="container">
  <div *ngFor="let blogPost of blogPosts; let i=index">
    <div *ngIf="i !== 0">
      <hr class="my-5">
    </div>
    <div class="row">
      <div class="col">
        <article>
          <section>
            <header style="" class="mb-4">
              <h1 style="display:inline" class="m-0 p-0">{{ blogPost.title }}</h1><small style="opacity:0.5" class="d-block d-sm-inline ml-sm-3">zuletzt bearbeitet am {{ blogPost.lastEdited | date }} von <a href="#" style="color:black"><strong>{{ blogPost.author.username }}</strong></a></small>
              <p class="mt-1 mt-sm-auto"><i class="fa fa-tags mr-2"></i><a *ngFor="let hashtag of blogPost.hashtags" href="#" class="badge badge-secondary mr-2">#{{ hashtag }}</a></p>
            </header>

            <div class="m-0 p-0" [innerHTML]="blogPost.body">
            </div>
            <div>
              <small class="heartUp"><a (click)="incrementHearts(i)" [ngStyle]="{'color':heartsUp.includes(blogPost.id) ? '#E63946' : 'rgba(0,0,0,0.5)'}"><i class="fa fa-heart mr-1"></i>{{ blogPost.hearts }}</a></small>
              <small class="likeUp"><a (click)="incrementLikes(i)" [ngStyle]="{'color':likesUp.includes(blogPost.id) ? '#3b5998' : 'rgba(0,0,0,0.5)'}"><i class="fa fa-thumbs-up mr-1"></i>{{ blogPost.likes }}</a></small>
              <small class="reply"><a><i class="fa fa-mail-reply mr-1"></i>Reply</a></small>
            </div>
            <div>
              <h2 class="my-3">Kommentare</h2>
              <div class="row no-gutters">
                <div class="col-auto mr-3">
                  <img src="https://semantic-ui.com/images/avatar/small/jenny.jpg" class="img-fluid">
                </div>
                <div class="col">
                  <h5 style="margin:0;padding:0;display:inline">Joe Henderson</h5><small style="display:inline;margin:0;padding:0;opacity:0.5" class="ml-2"> 1 day ago</small>
                  <div style="margin:0;padding:0">The hours, minutes and seconds stand as visible reminders that your effort put them all there.

                  Preserve until your next run, when the watch lets you see how Impermanent your efforts are.</div>
                  <div>and some other text</div>
                  <small style="margin:0;padding:0;opacity:0.5;margin-right:10px"><i class="fa fa-heart mr-1"></i>3</small>
                  <small style="margin:0;padding:0;opacity:0.5;margin-right:10px"><i class="fa fa-thumbs-o-up mr-1"></i>12</small>
                  <small style="margin:0;padding:0;opacity:0.5"><i class="fa fa-mail-reply mr-1"></i>Reply</small>
                </div>
              </div>
            </div>
          </section>
        </article>
      </div>
    </div>
  </div>
</div>

It uses the CSS framework Bootstrap, but this shouldnt matter. 它使用CSS框架Bootstrap,但这无关紧要。 So my site loads a lot of posts and every post has a like and a heart button which can be pressed up and down by the user. 因此,我的网站上加载了很多帖子,每个帖子都有一个点赞和一个心形按钮,用户可以上下按下它们。 If it's released then i update my post in the database. 如果发布了,那么我将更新数据库中的帖子。

I want to unsubscribe from the subscription at the end, but i cant. 我想在最后取消订阅。但是我不能。 I don't know whats the problem. 我不知道出什么问题了。 :( Nevertheless, i think the up and down voting is really bad written but how could it be done? Im thankful for any help. :) :(尽管如此,我认为上下投票的确写得不好,但是怎么办呢?我很感谢你的帮助。

Best regards, Sven 最好的问候,斯文

I'd go the route of creating a new Subject in your component where you have subscription calls. 我会选择在您具有订阅调用的组件中创建新主题的途径。

private ngUnsubscribe: Subject = new Subject();

Then, in the ngOnDestroy you call 然后,在ngOnDestroy中调用

ngOnDestroy() {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
    }

and before each subscription you do takeUntil: 并在每次订阅之前进行以下操作:

    this.likeSub = this.dataService.editBlogPost(this.blogPosts[index].id, { likes: this.blogPosts[index].likes })
.takeUntil(this.ngUnsubscribe)
.subscribe();

This is the method I use in my applications and you can read more about it here: 这是我在应用程序中使用的方法,您可以在此处了解更多信息:

Angular/RxJs When should I unsubscribe from `Subscription` Angular / RxJs我应该何时退订`Subscription`

I agree with @Filip, I went the same route as he described. 我同意@Filip,我走的路和他描述的一样。

Regarding your current problem. 关于您当前的问题。 If the functions incrementLikes() and incrementHearts() don't get called then those two subscriptions will definitely be undefined . 如果未调用函数incrementLikes()incrementHearts() ,则这两个订阅肯定是undefined

Sv En, if you don't execute incrementLikes() or incrementHearts() your variable not hav evalue. Sv En,如果不执行crementLikes()或incrementHearts(),则变量不具有evalue。 You can do 你可以做

ngOnDestroy() {
    if (this.likeSub)  //if exist
      this.likeSub.unsubscribe();
    if (this.heartSub)  //if exist
    this.heartSub.unsubscribe();
  }

Filip, you needn't use a Subject, just a boolean variable in the way Filip,您不需要使用Subject,而只是使用布尔变量

this.dataService.editBlogPost(..)
   .takeWhile(() => this.isAlive)
   .subscribe(...)

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

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