尝试防止订阅两次时出现 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 应用时出现限制错误