深入理解SocketStore类:高效管理WebSocket命令处理器在前端开发中,WebSocket是一种常用的实时通
在前端开发中,WebSocket是一种常用的实时通信技术。为了有效管理WebSocket命令的处理器,开发者通常会创建一套机制来注册、查找、和移除这些处理器。SocketStore
类正是为此目的设计的工具,它通过一种高效的方式组织这些处理器,使得WebSocket通信变得更加灵活和强大。
本文将详细介绍SocketStore
类的实现,分解各个代码片段,并一步步解析它们的功能和用途。
SocketStore
类概述
SocketStore
类的主要作用是管理与WebSocket命令相关的处理器。它通过一个内部的存储结构来管理这些处理器集合,每个命令ID(cmdID
)可以对应一个或多个处理器。SocketStore
类提供了添加、查找、移除和清理这些处理器的功能,确保WebSocket连接中的命令能够得到正确的处理。
主要功能
- 存储命令处理器:为特定命令ID注册处理器。
- 查找命令处理器:根据命令ID查找已注册的处理器集合。
- 移除命令处理器:删除特定命令ID的处理器,或清空所有处理器。
- 处理器缓存:缓存频繁访问的命令ID,以提升查询效率。
SocketStore
类实现
下面,我们将详细介绍SocketStore
类的每个部分,并解释它们的功能。
1. 构造函数:初始化类的基本结构
首先,让我们看看SocketStore
类的构造函数,它是类的起点,用于初始化存储和缓存机制。
constructor(maxCacheSize = 100) {
this.store = new Map(); // 主存储命令ID和处理器集合
this.cache = new Map(); // LRU缓存,缓存热点命令ID
this.maxCacheSize = maxCacheSize; // 缓存的最大大小
}
解释
-
this.store
:store
是一个Map
对象,用来存储命令ID和处理器集合的对应关系。Map
是JavaScript中的一种数据结构,允许我们使用键-值对来存储数据。在这里,键是命令ID (cmdID
),值是处理器集合。
-
this.cache
:cache
也是一个Map
,用于缓存最近访问的命令ID及其处理器集合。这样可以加快对这些命令的查找速度。- 这个缓存实现了LRU(Least Recently Used)策略,当缓存达到最大容量时,最不常用的命令ID会被移除。
-
this.maxCacheSize
:maxCacheSize
定义了缓存的最大容量。默认设置为100
,这意味着缓存中最多可以存储100个命令ID。如果超过这个数量,最不常用的命令ID会被移除。
2. 获取处理器集合:getStore
方法
getStore
方法用于根据命令ID查找已注册的处理器集合。如果命令ID已经被缓存,直接从缓存中获取,否则从主存储中查找。
getStore(cmdID) {
// 先检查缓存
if (this.cache.has(cmdID)) {
return this.cache.get(cmdID);
}
// 如果缓存中没有,检查主存储
const handlers = this.store.get(cmdID);
// 如果找到了处理器集合,更新缓存
if (handlers) {
this._updateCache(cmdID, handlers);
}
return handlers;
}
解释
-
检查缓存:
- 首先,
getStore
方法会检查缓存中是否有对应的命令ID。如果有,则直接返回缓存中的处理器集合。 - 通过缓存,可以快速获取到最近使用过的命令ID,提升查询效率。
- 首先,
-
检查主存储:
- 如果缓存中没有该命令ID,方法会继续检查主存储
store
。如果在store
中找到命令ID的处理器集合,就会返回这个集合。
- 如果缓存中没有该命令ID,方法会继续检查主存储
-
更新缓存:
- 如果从主存储中找到了处理器集合,那么会调用
_updateCache
方法,将这个命令ID和处理器集合添加到缓存中,以便下次快速访问。
- 如果从主存储中找到了处理器集合,那么会调用
-
返回处理器集合:
- 最终,方法返回找到的处理器集合。如果命令ID不存在,返回值将是
undefined
。
- 最终,方法返回找到的处理器集合。如果命令ID不存在,返回值将是
3. 添加处理器:addStore
方法
addStore
方法用于将处理器注册到指定的命令ID下。如果命令ID对应的处理器集合不存在,它会创建一个新的集合。
addStore(cmdID, handler, isCmdHandler = true) {
// 尝试获取现有的处理器集合
let handlers = this.getStore(cmdID);
if (!handlers) {
handlers = new Set();
this.store.set(cmdID, handlers);
}
// 为处理器定义属性
Object.defineProperty(handler, 'isCmdHandler', {
value: isCmdHandler,
configurable: true,
writable: false,
});
// 如果处理器是命令处理器,并且还没有 CmdHandler 属性,则创建一个新的 CmdHandler
if (isCmdHandler && !handler.CmdHandler) {
Object.defineProperty(handler, 'CmdHandler', {
value: new CmdHandler(handler),
configurable: true,
writable: false,
});
}
// 将处理器添加到集合中
handlers.add(handler);
// 更新缓存
this._updateCache(cmdID, handlers);
return this;
}
解释
-
获取或创建处理器集合:
- 首先调用
getStore
获取现有的处理器集合。如果集合不存在,意味着这是第一次为该命令ID添加处理器,此时会创建一个新的Set
集合,并将其存储在store
中。
- 首先调用
-
定义属性:
- 使用
Object.defineProperty
为处理器定义属性,确保处理器的行为符合预期。例如,isCmdHandler
属性标识了这个处理器是否为命令处理器。
- 使用
-
创建
CmdHandler
实例:- 如果处理器是命令处理器 (
isCmdHandler
为true
),且还没有关联的CmdHandler
属性,则为它创建一个CmdHandler
实例。
- 如果处理器是命令处理器 (
-
添加处理器到集合中:
- 将处理器添加到对应命令ID的处理器集合中,然后更新缓存,以便下次快速访问。
4. 移除处理器:removeStore
方法
removeStore
方法用于从存储中移除某个命令ID的指定处理器,或删除整个命令ID的处理器集合。
removeStore(cmdID, fn) {
const handlers = this.getStore(cmdID);
if (handlers === undefined) return;
if (fn !== undefined) {
if (handlers.delete(fn)) clearEffect(fn);
if (handlers.size !== 0) return;
}
// 如果集合为空或未指定特定处理器,删除命令ID
this.store.delete(cmdID);
this.cache.delete(cmdID); // 同时从缓存中移除
}
解释
-
获取处理器集合:
- 首先调用
getStore
获取指定命令ID的处理器集合。如果集合不存在,直接返回。
- 首先调用
-
移除特定处理器:
- 如果传入了具体的处理器
fn
,会尝试从集合中删除这个处理器,并清除它的副作用。如果集合中还有其他处理器,会提前返回,不会删除整个命令ID。
- 如果传入了具体的处理器
-
删除命令ID:
- 如果集合为空或未指定处理器
fn
,会删除整个命令ID对应的处理器集合,并从缓存中移除这个命令ID。
- 如果集合为空或未指定处理器
5. 清空所有处理器:clearStore
方法
clearStore
方法用于清空SocketStore
中的所有处理器和缓存。
clearStore() {
this.store.forEach((handlers) => handlers.forEach((fn) => clearEffect(fn)));
this.store.clear();
this.cache.clear(); // 同时清空缓存
}
解释
-
清理每个处理器的副作用:
- 遍历
store
中的每个命令ID,并逐个清理其处理器的副作用。这确保了所有处理器在被移除前都得到了适当的清理。
- 遍历
-
清空存储和缓存:
- 清理完副作用后,清空
store
和cache
,释放所有已存储的数据。
- 清理完副作用后,清空
6. 更新缓存:_updateCache
方法
_updateCache
方法用于管理命令ID的缓存,确保缓存的高效性和容量控制。
_updateCache(cmdID, handlers) {
if (this.cache.has(cmdID)) {
this.cache.delete(cmdID); // 先删除旧的位置
}
this.cache.set(cmdID, handlers); // 插入到最新位置
// 如果缓存超过最大限制,移除最老的记录
if (this.cache.size > this.maxCacheSize) {
const oldestKey = this.cache.keys().next().value;
this.cache.delete(oldestKey);
}
}
解释
-
管理缓存位置:
- 如果命令ID已经在缓存中存在,首先删除旧的位置,然后将其重新插入到最新的位置。这是为了实现LRU(Least Recently Used)策略,使得最近访问的命令ID保持在缓存中。
-
控制缓存大小:
- 每次更新缓存时,SocketStore类会检查缓存的大小是否超过了
maxCacheSize
。如果超过了,则移除最早加入缓存的命令ID,确保缓存的大小在限制范围内。
- 每次更新缓存时,SocketStore类会检查缓存的大小是否超过了
7. 清除处理器的副作用:clearEffect
函数
clearEffect
函数用于在移除处理器时清理其副作用,确保不再保留多余的属性或引用。
function clearEffect(handler) {
if (handler) {
delete handler.isCmdHandler;
delete handler.CmdHandler;
}
}
解释
-
清理属性:
clearEffect
函数使用delete
操作符删除处理器对象上的isCmdHandler
和CmdHandler
属性。这是为了在移除处理器时,防止遗留不必要的属性或引用,确保内存的有效利用。
总结
通过详细解析SocketStore
类的每个部分,我们可以看到它是如何高效地管理WebSocket命令的处理器集合的。SocketStore
类不仅能够动态地注册和管理命令ID下的处理器,还能够通过缓存机制快速响应对热点命令ID的访问。
这种设计使得SocketStore
类在处理大量命令和复杂场景时表现出色,为WebSocket通信的稳定性和高效性提供了有力支持。
转载自:https://juejin.cn/post/7403735158492872738