【问题标题】:Socket.io event listener called multiple times (angular 9)多次调用 Socket.io 事件侦听器(角度 9)
【发布时间】:2022-01-25 03:38:40
【问题描述】:

前端(Angular 9)

我正在使用 Socket.io 和 Angular 9 实现聊天功能。创建了一个服务并调用套接字连接和事件处理,如下所示。

 @Injectable({
    providedIn: 'root',
  })

  export class ChatService {
    private socket;

    public channelError = new BehaviorSubject(null);
    public channelHistory = new BehaviorSubject(null);
    public channelMessage = new BehaviorSubject(null);
    public channelReaction = new BehaviorSubject(null);

    constructor(
    ) {}

    establishSocketConnection = (userId) => {
      this.socket = io(`${chatUrl}/chat`, {
        path: '/socket.io',
        query: {
        user: userId,
        },
      });

      this.socket.on('channel-history', (threads: any) => {
        this.channelError.next('');
        this.channelHistory.next(threads);
      });

      this.socket.on('message-local', (message: any) => {
        this.channelMessage.next(message);
      });
    }

    // socket (emit) events
    public emitMessage = (message, authorId, channel) => {
    this.socket.emit('message', message, authorId, channel);
    }

    public loadChannelHistory = (channelId) => {
    this.socket.emit('load-channel-history', channelId);
    }

    // socket (on) event listeners
    public getChannelHistory(): Observable<any> {
    return this.channelHistory.asObservable();
    }

    public getMessage(): Observable<any> {
    return this.channelMessage.asObservable();
    }
 }

我在登录后调用方法“建立套接字连接”一次以建立套接字连接并注册套接字侦听器。我已经在这个方法中注册了所有的socket监听器。

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { LoginService } from '../../services/login.service';
import { StorageService } from '../../services/storage.service';
import { ProductTypeService } from '../../services/product-type.service';
import { UserSidebarService } from '../../services/user-sidebar.service';
import { Storage } from '@ionic/storage';
import { ChannelTypeService } from 'src/app/services/channel-type.service';
import { ChatService } from 'src/app/services/chat.service';
@Component({
  selector: 'app-menu',
  templateUrl: './menu.page.html',
  styleUrls: ['./menu.page.scss'],
})
export class MenuPage implements OnInit {
  activeSettingChild: any;
  channelMaintitle: any;
  channels: any;
  selectedChat: any;
 
  constructor(
    private router: Router,
    public loginServ: LoginService,
    public storageServ: StorageService,
    public productTypeServ: ProductTypeService,
    public userSidebarServ: UserSidebarService,
    public storage: Storage,
    private channelTypeServ: ChannelTypeService,
    private chatService: ChatService
  ) {
    
  }

  ngOnInit() {
    //establish socket connection
    let userId = this.storageServ.get('userId');
    if (userId) {
      this.chatService.establishSocketConnection(userId);
    }

    this.selectedChat = localStorage.getItem('selectedChat');
    this.getAllChannels();
  }

  getAllChannels() {
    this.channelTypeServ.getAllChannelTypes().subscribe(
      (channel: any) => {
        this.channels = channel.data.channels;
      },
      (error) => { }
    );
  }


  onSelectChannel(channel) {
    this.activeSettingChild = channel.slug;
    this.storageServ.set('activeSettingChild', channel.slug);
    this.storageServ.set('lockedPageContent', channel.lockedPageContent);
    this.storageServ.set('channelTitle', channel.title);
    this.storageServ.set('channelId', JSON.stringify(channel));
    this.channelMaintitle = channel.settingId.title;
    this.storageServ.set('channelMaintitle', this.channelMaintitle);
    this.router.navigate(
      [`/platinum-chat/${this.selectedChat}/${'channel/' + channel.slug}`],
      { replaceUrl: true }
    );
  }
}

我在一个组件中使用此聊天服务,如下所示。 组件:

import { Component, OnInit } from '@angular/core';
import { ChatService } from 'src/app/services/chat.service';
@Component({
  selector: 'app-platinum-chat',
  templateUrl: './platinum-chat.page.html',
  styleUrls: ['./platinum-chat.page.scss'],
})
export class PlatinumChatPage implements OnInit {
  message: string;
  authorId: any;
  channel: any;
  threadChat: any[] = [];
  channelError: string = '';

  constructor(
    private chatService: ChatService,
  ) {
    this.channel = localStorage.getItem('channelId');
  }

  ngOnInit() {
    //load channel history
    this.loadChannelHistory();

    // get new message listener
    this.chatService.getMessage().subscribe((msg: any) => {
        this.threadChat.push(msg);
    });

    // error listener
    this.chatService.getChannelError().subscribe(errorMessage => {
      this.channelError = errorMessage;
    });

    //channel history listener
    this.chatService.getChannelHistory().subscribe((threads: any) => {
      this.threadChat = threads;
    });

  }

  loadChannelHistory(){
    const channelId = JSON.parse(this.channel);
    this.chatService.loadChannelHistory(channelId && channelId._id || null);
  }

  onSendMessage() {
      this.chatService.emitMessage(this.message, this.authorId, this.channel);
  }
}

问题是,当我发送新消息时,它会多次“在消息本地”调用事件侦听器。正如我已经围绕这个问题进行了调试,根据一些建议,重复事件侦听器注册存在问题。就我而言,我不会多次调用方法“建立套接字连接”,然后它是如何注册重复侦听器(消息本地)并在新消息上多次调用。

注意:不是从服务器端发出的。我只从服务器端发送单个发射,但它在前端被多次调用。

在这里我记录了我的问题 https://www.loom.com/share/d9142c73c6c54cb58802ac3edf704bc5

我不明白当前代码库有什么问题。

你们能帮我解决这个问题吗?提前致谢!!

【问题讨论】:

  • 您是否可以在 stackblitz 上创建一个最小的工作示例?
  • 还包括显示消息的 html 的相关部分。

标签: angular socket.io angular9


【解决方案1】:

为了它的价值,不要让订阅闲置。每次加载组件时都会添加订阅,但不会删除。这可能,但可能不是原因。无论如何,我重构并实现了一种取消订阅()的方法,试一试。

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
  export class PlatinumChatPage implements OnInit, OnDestroy {
    message: string;
    authorId: any;
    channel: any;
    threadChat: any[] = [];
    channelError: string = '';
    subs = [];

    constructor(
      private chatService: ChatService,
    ) {
      this.channel = localStorage.getItem('channelId');
    }

    ngOnDestroy() {
      this.subs.forEach(sub => sub.unsubscribe());
    }

    ngOnInit() {
      //load channel history
      this.loadChannelHistory();
  
      // get new message listener
      const chatSub = this.chatService.getMessage().subscribe((msg: any) => {
          this.threadChat.push(msg);
      });
  
      // error listener
      const errorSub = this.chatService.getChannelError().subscribe(errorMessage => {
        this.channelError = errorMessage;
      });
  
      //channel history listener
      const historySub = this.chatService.getChannelHistory().subscribe((threads: any) => {
        this.threadChat = threads;
      });
      this.subs.push(chatSub, errorSub, historySub);
    }
  
    loadChannelHistory(){
      const channelId = JSON.parse(this.channel);
      this.chatService.loadChannelHistory(channelId && channelId._id || null);
    }
  
    onSendMessage() {
        this.chatService.emitMessage(this.message, this.authorId, this.channel);
    }
  }

【讨论】:

  • Joosep.P - 您的解决方案对我有用。感谢您给我正确的解决方案。非常感谢。现在问题消失了,监听器只调用一次。
猜你喜欢
  • 2014-09-06
  • 2020-12-23
  • 1970-01-01
  • 2021-03-09
  • 1970-01-01
  • 2018-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多