Skip to content

KeyStorage 与变更监听 ​

KeyStorage<T> 把一个类型化值绑定到一个字符串键。读写同步执行,通知通过事件总线异步投递。它不会自动监听原生浏览器 storage 事件。

后端与事件总线需要分别选择:共享后端不会共享缓存值或订阅。两个实例即使使用同一个 key 和后端,若各用默认总线,在调用 reload() 前仍可能保留不同的缓存值。需要两个实例都观察到通过 KeyStorage 进行的写入时,还需共享总线。

选项 ​

new KeyStorage<T>(options: KeyStorageOptions<T>):

选项默认值含义
key: string必填后端存储键。
storage?: StoragegetStorage()浏览器 localStorage,非浏览器新建内存存储。
serializer?: Serializer<string, T>jsonSerializer读写及自动广播快照使用的字符串编解码器。
eventBus?: TypedEventBus<StorageEvent<T>>新建 SerialTypedEventBus('KeyStorage:' + key)仅名称相同不会共享实例。新建的总线由 destroy() 关闭,传入的总线不会。
defaultValue?: Tnull后端缺值时返回,不会自动持久化。

读写与生命周期 ​

方法返回值行为
get()T | null返回非空缓存;否则读取并反序列化后端,缺失时返回默认值。无法反序列化的值会被删除并告警,按缺失处理。
reload()T | null绕过缓存重新读取后端(用于另一个标签页可能已写入、但其事件尚未到达的值)。存储文本未变时保留缓存对象;键不存在时返回默认值。
set(value: T)void读取旧值、序列化/快照、写后端、更新缓存、投递 {oldValue, newValue}。set(undefined) 等同 remove()。
remove()void读取旧值、删除后端键、清空缓存、投递 newValue: null;随后 get 可能返回默认值。
addListener(handler)RemoveStorageListener = () => void注册具名 EventHandler<StorageEvent<T>>;返回函数仅在该名称下注册的仍是此处理器时将其移除。
destroy()void移除此实例的内部缓存监听器,并关闭此实例创建的总线(默认总线,或子类用受保护的 ownEventBus() 标记的总线)。不删除键,也不关闭通过 eventBus 传入的总线。

StorageEvent<T> 包含可选 newValue、oldValue,均允许 null。StorageListenable<T> 提供 addListener。请使用唯一处理器名称:底层总线拒绝同名注册,此时返回的移除函数不做任何事,绝不会移除占用该名称的监听器。实例内部的缓存监听器先于所有其他监听器执行(order 为 Number.MIN_SAFE_INTEGER),因此慢监听器不会让较旧事件覆盖较新的缓存值。销毁拥有的总线前自行解绑外部监听器。

后端读写、JSON 解析、序列化失败同步传出;通知失败后不会回滚写入。emit 拒绝会被捕获并 console.warn,普通串行处理器失败则已由总线隔离。非空缓存不会因直接修改后端而刷新;调用 reload() 重新读取。get() 返回对象引用,修改引用不会自动持久化。

共享与广播 ​

显式传入同一个本地总线以协调多个实例。跨上下文通知使用 BroadcastTypedEventBus。若广播总线尚无 wire transformer,KeyStorage 会安装基于序列化器的转换器,在本地处理器修改对象前快照序列化新值,接收方恢复自定义类型,并在 DataCloneError 时回退到字符串快照。无效旧快照会被视为不可用,不丢弃有效新值。deserializeLegacy 可解码旧结构化消息。

共享广播总线在整个生命周期必须使用相同存储键;使用自动转换时还必须使用相同序列化器实例(默认 JSON 实例会统一)。违反约束会在构造时抛错。已有自定义转换器仍由调用者负责。接收到事件只更新内存缓存,不写入接收方后端。销毁 KeyStorage 保留共享总线所有权。

完整示例 ​

ts
import { KeyStorage, InMemoryStorage } from '@ahoo-wang/fetcher-storage';

const settings = new KeyStorage<{ theme: string }>({
  key: 'settings',
  storage: new InMemoryStorage(),
  defaultValue: { theme: 'system' },
});
const removeListener = settings.addListener({
  name: 'settings-ui',
  handle: event => {
    console.log(event.newValue);
  },
});
settings.set({ theme: 'dark' });
console.assert(settings.get()?.theme === 'dark');
settings.remove();
console.assert(settings.get()?.theme === 'system');
removeListener();
settings.destroy();

公开符号与源码 ​

符号实现
StorageEventkeyStorage.ts:28
RemoveStorageListenerkeyStorage.ts:36
StorageListenablekeyStorage.ts:38
KeyStorageOptionskeyStorage.ts:52
KeyStoragekeyStorage.ts:91

包索引

基于 Apache License 2.0 发布。