尝试防止订阅两次时出现 ObjectUnsubscribedError

Posted

技术标签:

【中文标题】尝试防止订阅两次时出现 ObjectUnsubscribedError【英文标题】:ObjectUnsubscribedError when trying to prevent subscribing twice 【发布时间】:2016-10-31 02:46:26 【问题描述】:

我有一个服务和一个使用它的组件:

PagesService PagesListComponent

PagesService 中,我有一个Pages 数组。我通过BehaviorSubject 通知数组中的更改,它们都订阅了。

PagesService 提供 bootstrap,仅共享一个实例。那是因为我需要保留数组,而不是每次需要时都下载页面。

代码如下:

pages.service.ts

import  Injectable  from '@angular/core';
import  BehaviorSubject  from 'rxjs/Rx';
import  Http, Response  from '@angular/http';

import  Page  from './../models/page';

@Injectable() export class PagesService 

    public pages$: BehaviorSubject<Page[]> = new BehaviorSubject<Page[]>([]);
    private pages: Page[] = [];

    constructor(private http: Http)  

    getPagesListener() 
        return this.pages$;
    
    getAll() 
        this.http.get('/mockups/pages.json').map((res: Response) => res.json()).subscribe(
            res =>  this.resetPagesFromJson(res); ,
            err =>  console.log('Pages could not be fetched'); 
        );
    

    private resetPagesFromJson(pagesArr: Array<any>) 
        // Parses de Array<any> and creates an Array<Page>
        this.pages$.next(this.pages);
    

pages_list.component.ts

import  Component, OnInit  from '@angular/core';
import  Router  from '@angular/router-deprecated';
import  BehaviorSubject  from 'rxjs/Rx';

import  PagesService  from '../../shared/services/pages.service';
import  GoPage  from '../../shared/models/page';

@Component(
    moduleId: module.id,
    selector: 'go-pages-list',
    templateUrl: 'pages_list.component.html',
    styleUrls: ['pages_list.component.css']
)
export class PagesListComponent implements OnInit 
    pages$: BehaviorSubject<GoPage[]>;
    pages: GoPage[];
    constructor(private pagesService: PagesService, private router: Router)  

    ngOnInit() 
        this.pages$ = this.pagesService.getPagesListener();
        this.pages$.subscribe((pages) =>  this.pages = pages; console.log(pages) );
        this.pagesService.getAll();
    
    ngOnDestroy() 
        this.pages$.unsubscribe();
    

这第一次运行良好,订阅 onInit 和取消订阅 onDestroy。但是当我返回列表并尝试再次订阅(获取 pages[] 的当前值并监听未来的更改)时,它触发错误 EXCEPTION: ObjectUnsubscribedError

如果我不取消订阅,每次我进入列表时,都会堆叠一个新订阅,并在收到 next() 时触发所有订阅。

【问题讨论】:

【参考方案1】:

我会以这种方式获得订阅并取消订阅,而不是直接针对主题:

ngOnInit() 
  this.pages$ = this.pagesService.getPagesListener();
  this.subscription = this.pages$.subscribe((pages) =>  // <-------
    this.pages = pages; console.log(pages);
  );
  this.pagesService.getAll();


ngOnDestroy() 
    this.subscription.unsubscribe(); // <-------

【讨论】:

你能提一下为什么在注入的主题引用上直接调用 unsubscribe 不起作用吗? "Subject 类中的 unsubscribe 方法实际上并没有取消订阅任何内容。相反,它会将主题标记为已关闭,并将其内部数组 subscribedobservers  设置为 null" 更多详细信息:blog.angularindepth.com/rxjs-closed-subjects-1b6f76c1b63c跨度> 我刚刚尝试了一个 eventEmitter,我需要取消订阅并重新订阅它并且它工作得很好......但我仍然有一个问题:为什么 this.subscription 可以取消订阅并重新订阅没有问题同时,如果您直接对事件/可观察对象执行此操作,则无法重新订阅? 结论:将订阅保存在VARIABLE中,并在其上调用unsubscribe方法(不是在您订阅的函数上)!非常感谢你!【参考方案2】:

.subscribe() 返回一个订阅

您应该使用它来取消订阅

例如 Parent 有一个 reloadSubject: Subject;

child1 -> 订阅 child2 -> 订阅

child1 - "WORKS" -> 取消订阅他的订阅

ngOnInit 
  sub: Subscription = parent.subscribe();

onDestroy
  this.sub.unsubscribe();

child2 - “不工作” -> 取消订阅整个父母

ngOnInit 
  parent.subscribe();


onDestroy
  parent.unsubscribe();

如果您对父级调用取消订阅,则两个子级都消失了。 如果您取消订阅从 .subscribe() 获得的订阅 那么只有一个孩子被取消订阅。

如有错误请指正!

【讨论】:

以上是关于尝试防止订阅两次时出现 ObjectUnsubscribedError的主要内容,如果未能解决你的问题,请参考以下文章

创建订阅时出现“CKSubscriptionTypeRecordZone 订阅与订阅选项 7 不兼容”

创建对 URL 端点的订阅时出现“pubsub 错误 INVALID_ARGUMENT”

Webflux,使用Websocket如何防止订阅两次反应式redis消息操作

尝试使用 Azure CLI 创建 Web 应用时出现限制错误

两次调用 WebApi 时出现 ServerProtocolViolation 错误

尝试被计数跟踪时出现 Instagram 错误