面试题答案
一键面试缓存策略设计
-
数据分类:
- 用户配置:更新频率低,缓存有效期长。可考虑使用
localStorage
或IndexedDB
进行持久化存储,因为这类数据即使页面刷新或关闭重新打开也应保持。 - 动态图表数据:更新频率中等,缓存有效期适中。可以在内存中缓存(例如在JavaScript变量中),同时结合
IndexedDB
进行持久化备份。内存缓存用于快速访问,当页面刷新等情况导致内存数据丢失时,从IndexedDB
中恢复。 - 频繁更新的实时消息:更新频率高,缓存有效期短。采用内存缓存为主,同时利用
Service Worker
拦截网络请求,在网络不可用时提供最近的缓存数据。
- 用户配置:更新频率低,缓存有效期长。可考虑使用
-
技术手段:
- Service Worker:
- 用途:主要用于拦截网络请求,实现离线缓存和提高页面加载速度。对于实时消息等频繁更新的数据,Service Worker 可以在网络请求失败时,从缓存中返回最近的数据。
- 实现:在 Service Worker 脚本中,通过
caches.open()
打开缓存空间,使用fetch
事件监听器拦截请求,判断请求的资源是否在缓存中。如果在缓存中且未过期(可通过自定义的缓存过期逻辑判断),则返回缓存数据;否则,发起网络请求,并在请求成功后更新缓存。
- IndexedDB:
- 用途:作为持久化存储方案,适合存储用户配置和动态图表数据等需要长期保存的数据。
- 实现:创建数据库和对象仓库,根据数据类型定义不同的对象仓库。例如,为用户配置创建一个对象仓库,为动态图表数据创建另一个对象仓库。使用
IDBRequest
进行数据的增删改查操作。在更新数据时,先更新IndexedDB
中的数据,再更新内存中的缓存,确保数据一致性。
- 内存缓存:
- 用途:在JavaScript运行时环境中缓存数据,提供最快的访问速度。
- 实现:在JavaScript模块中定义变量来存储缓存数据。例如,对于动态图表数据,可以在一个模块中定义
let chartDataCache = null;
,获取数据时先检查该变量是否有值且未过期,有则直接返回,否则从IndexedDB
或网络获取并更新缓存。
- Service Worker:
处理缓存冲突
- 版本控制:为不同类型的数据设置版本号。当数据更新时,同时更新版本号。在读取缓存数据时,首先检查版本号是否匹配。如果不匹配,说明数据已过期或被更新,需要重新获取最新数据。例如,在存储用户配置到
IndexedDB
时,同时存储一个版本号字段configVersion
,每次配置更新时递增该版本号。 - 唯一标识:为每种数据类型定义唯一标识。在缓存和更新数据时,根据唯一标识进行操作。例如,对于动态图表数据,以图表的ID作为唯一标识。如果有多个页面同时请求和更新图表数据,都基于这个唯一标识进行操作,避免不同页面间的数据冲突。
处理数据过期
- 时间戳标记:在缓存数据时,同时记录数据的创建时间或过期时间。例如,在存储实时消息到内存缓存时,为每个消息对象添加一个
timestamp
字段记录创建时间。在获取缓存数据时,根据当前时间和timestamp
计算数据是否过期。 - 缓存清理:对于过期的数据,及时清理缓存。可以在每次获取数据时检查过期情况并清理,也可以设置一个定时任务定期清理缓存。例如,使用
setInterval
函数每隔一段时间(如10分钟)检查并清理过期的实时消息缓存。对于IndexedDB
中的过期数据,通过IDBRequest
删除相应的记录。