我有一个聊天应用程序,可以说我正在与Jane聊天。当我打开与Jane的聊天屏幕时,她向我发送了一条消息,我正确地收到了它。但是,如果我关闭该消息,然后再次打开它,Jane向我发送一条消息,则我收到了它的两个副本。当我关闭屏幕并再次打开它时,Jane发送一条消息,我得到了它的三个副本。
似乎在关闭屏幕时,没有适当取消订阅该可观察对象。当我检查后端时,一次仅发送一条消息,从不发送多条消息。
export class ChatComponent implements OnInit, AfterViewInit, OnDestroy {
private _messages: Subscription;
private message = ''; //for the [(ngModel)]
public ngOnInit(): void {
// below I am subscribing to the observable
this._messages = this.chatService.getMessages$().subscribe((message: Message[]): void => {
console.lot('msg received', message);
this.messages$ = message;
});
}
public async sendMessage(): Promise<void> {
const message = await this._bundleMessage(); // formats the message
this.chatService.sendMessage(message);
this.message = '';
}
public ngOnDestroy(): void {
this._messages.unsubscribe();
}
}
private messages: Message[] = new Array<Message>();
private readonly bsMessages$: BehaviorSubject<Message[]> = new BehaviorSubject<Message[]>(this.messages);
public getMessages$(): Observable<Message[]> {
return this.bsMessages$.asObservable();
}
public async setAsActiveConversation(user: UserData): Promise<void>{
this._incomingMessages = this.receiveMessages().subscribe();
const { id } = user;
this.activeConversation = await this.conversationStorage.get(id);
console.log('after setting the active conversation', this.activeConversation);
if (this.activeConversation === null) {
await this._newConversation(user);
await this.conversationStorage.set(id, this.activeConversation);
this.messages = this.activeConversation.messages;
this.bsMessages$.next(this.messages);
} else {
await this.activeConversation.messages.forEach((msg: Message): void => {
if (msg.image) {
msg.image = this.webView.convertFileSrc(msg.image);
} else {
msg.image = '';
}
// console.log('after the if statement', this.activeConversation);
this.messages = this.activeConversation.messages;
this.bsMessages$.next(this.messages);
});
}
}
public async sendMessage(msg: Message): Promise<void> {
this.socket.emit('message', msg); //emits to server
this.activeConversation.messages.push(msg); //adds message to array
this.conversationStorage.set(this.activeConversation.id, this.activeConversation); //saves message locally
this.bsMessages$.next(this.messages); //signals to update
}
如果您需要更多信息,请告诉我,但我认为可以归结为这一点
编辑:添加了更多代码来帮助澄清一些注释。另外,当我记录数组见上文的结果时,我可以看到有重复项被添加到数组中。不只是视觉上当它发送2条以上的消息时,我看到数组长度增加了2条以上
答案 0 :(得分:1)
错误在这里:
public async setAsActiveConversation(user: UserData): Promise<void>{
this._incomingMessages = this.receiveMessages().subscribe(); //<--- here
const { id } = user;
我并没有取消订阅,这导致了内存泄漏!
在chat.component.ts
中我添加了
public ngOnDestroy(): void {
this.chatService.setLastMessage();
this._messages.unsubscribe();
this.chatService._incomingMessages.unsubscribe(); // <---
}
答案 1 :(得分:0)
尽管您可以将.subscribe()
的返回值存储在局部变量中并最终自己调用.unsubscribe()
,但这通常很麻烦且容易出错。相反,请考虑以下方法:
// RxJs pipeable operator for subscribing until component fires onDestroy
export function takeUntilComponentDestroyed(component: OnDestroy): MonoTypeOperatorFunction<any> {
const componentDestroyed = (comp: OnDestroy) => {
const oldNgOnDestroy = comp.ngOnDestroy;
const destroyed$ = new ReplaySubject<void>(1);
comp.ngOnDestroy = () => {
oldNgOnDestroy.apply(comp);
destroyed$.next(undefined);
destroyed$.complete();
};
return destroyed$;
};
return pipe(
takeUntil(componentDestroyed(component))
);
}
这为RxJ定义了一个自定义pipe
,这将允许我们take
直到销毁指定的组件。该组件必须必须像这样实现OnDestroy
:
export class SomeComponent implements OnInit, OnDestroy {
...
// OnDestroy interface contract requires:
ngOnDestroy() { }
...
}
现在您已经设置了要实施OnDestroy的组件,则可以使用我们新的自定义管道自动take
,直到其被破坏为止,如下所示:
observable$.pipe(
takeUntilComponentDestroyed(this)
).subscribe(value => {
console.log("Value emits until component destroyed", value)
});
现在,您可以在想收听的任何地方使用该管道,而不必担心取消订阅!