聊天室的设计思路

1,061 阅读2分钟

背景

最近发现一款有意思的聊天产品discord,对此预研了类似的产品stream-chat及其social messaging demo的源码,根据其原理总结出一套设计思路

demo效果

image.png image.png

设计思路

1.视图层

总的设计为左右结构,如图: image.png 左模块:MessagingChannelListHeader用户信息、ChannelList频道列表 右模块:CreateChannel搜索用户区、ChannelInner频道具体内容(包括对话窗口和侧边栏)

2.数据层

数据层核心结构如图:

image.png

举个聊天室例子

image.png

按步骤拆解见下文

2.1第一步:建立双向通信连接(WebSocket协议)

由于聊天室需要实时同步每个用户窗口交互的效果,要求客户端和服务端能够双向通信,因此需要建立WebSocket连接。用于服务端主动向客户端发送数据。客户端可以使用ws建立连接。
不过,前端主动向后端发送数据的方式是采用https协议,https和WebSocket是兼容的。

2.2第二步:生成聊天室实例(client对象)

一个聊天室会生成一个client实例,client上有几个核心属性和方法如图: image.png

client.on和client.off

on和off负责注册注销通用事件和聊天室事件,比如更新频道、删除频道、消息未读状态处理等。调用方式有两种(区别见client.dispatchEvent),如下:
第一种:client.on(handleEvent) 注册通用事件
第二种:client.on('xxx', handleEvent) 注册聊天室事件

client.listens

listens是一个事件集合,如图: image.png
all:由 client.on(handleEvent) 注册,每调用一次就往all数组中添加一个事件元素。
聊天室事件:由client.on('xxx', handleEvent)注册,每调用一次就往聊天室事件数组中添加一个事件元素。比如,client.on('channel.update', handleEvent)调用n次,listens['channel.update']长度为n。

client.dispatchEvent

dispatchEvent负责派发事件,派发时机为websocket.onmessage触发时,根据后端返回的event.type,调用listens['event.type']数组中的所有事件,同时每次都会调用listens['all']中的所有事件

client.queryChannels

queryChannels负责查询并更新频道列表,返回channels集合,每个元素都是一个channel实例(见下文)

2.3第三步:生成频道实例(channel对象)

频道列表中,每一个频道对应一个channel实例,channel上有几个核心属性和方法如图: image.png

channel.on、channel.off和channel.listens

on、off和listens的原理跟client实例的一模一样。其中,listens事件集合也是通用事件和聊天室事件,在 client.dispatchEvent执行时候执行的,执行原理也一样。
ps:channel主要负责message相关事件

channel.state

state是一个对象,负责记录channel实例的状态,比如改频道的人员数量、未读状态等,在前后端通信后会被更新。

参考

social messaging源码

stream-chart源码

WebSocket教程