AmplifyJS 源码解析:amplify.store 特性检测与 JSON 序列化设计
AmplifyJS 源码解析:amplify.store 特性检测与 JSON 序列化设计
【免费下载链接】amplifyAmplifyJS项目地址: https://gitcode.com/gh_mirrors/amp/amplify
AmplifyJS 是一套专注数据管理与应用通信的轻量 JavaScript 组件库,其中 amplify.store 是最实用的模块之一:它用一条统一的 API 完成客户端持久化存储。本文从源码角度解析 amplify.store 的特性检测机制与 JSON 序列化设计,看看它如何在从 IE 5 到现代浏览器的环境中自动选出最佳存储方案,又如何把复杂对象安全地"塞进"只能存字符串的浏览器存储中。
amplify.store 是什么:一条 API 搞定浏览器存储 🧰
AmplifyJS 的设计理念是"让开发者专注业务,而不是纠结兼容性"。amplify.store 正是这一理念的典型代表:
- 支持 IE 5+、Firefox 2+、Safari 4+、Chrome、Opera 10.5+ 等横跨十余年的浏览器
- 无论底层是 localStorage、sessionStorage,还是老旧的 userData,你都只需要记住同一组 API
- 存、取、删、批量导出,全部由一个入口完成
看一个最常用的用法(摘自项目自带示例):
// 存一个对象,amplify 自动挑选最合适的存储技术 amplify.store( "storeExample1", { foo: "bar" } ); // 按 key 取回,自动反序列化 var value = amplify.store( "storeExample1" ); value.foo; // "bar" // 不传 key,一次性导出所有数据 var all = amplify.store();这段代码来自 demo/store/implicit/demo.js,完整的 API 说明见官方文档 docs/amplify.store.md。
源码架构:从统一入口到多存储后端 🏗️
打开 src/store.js,你会发现 amplify.store 本身只是一个"路由器":
- 它维护一张存储类型注册表
store.types - 每次调用,根据
options.type(或默认类型)把请求转交给对应的后端 store.addType()负责注册新类型,并自动生成amplify.store.xxx()这样的快捷方法(src/store.js#L13-L24)
这种"插件式"架构让扩展新存储后端变得非常简单——项目内置的五个存储类型,全部都是通过 addType 注册进来的。
特性检测设计:自动挑选最优存储方案 🔍
五种存储类型的探测顺序
amplify.store 能"通吃"所有浏览器,靠的不是一堆if (isIE)式的浏览器嗅探,而是特性检测。它按照"越先进越优先"的顺序依次探测:
| 顺序 | 存储类型 | 适用浏览器 |
|---|---|---|
| 1 | localStorage | IE 8+、Firefox 3.5+、Chrome、Safari 4+ 等 |
| 2 | sessionStorage | 同上,会话级存储 |
| 3 | globalStorage | Firefox 2/3 时代的过渡方案 |
| 4 | userData | IE 5-7 的专属方案 |
| 5 | memory | 内存兜底,保证 API 永远可用 |
第一个探测成功的类型,会自动成为amplify.store()的默认存储后端。
探测技巧:写入再删除的"试运行"
特性检测最精妙的部分在 src/store.js#L105-L115。单纯检查window.localStorage是否存在远远不够,因为 Safari 5 的隐私浏览模式会"伪装"支持 localStorage,但实际写入必然失败。所以源码采用了写入-删除实测法:
- 先尝试写入一个测试项
- 再立即删除它
- 两步都成功,才判定该存储真正可用
整个过程包裹在 try/catch 中,同时兼顾了 file:// 协议下 Firefox 的异常行为。任何一步报错都会静默跳过,继续探测下一个类型,绝不打扰用户。
特性检测失败时的优雅降级
探测失败的场景同样处理得细腻:
- 只有 localStorage 不可用时,才回退到 Firefox 专用的 globalStorage,并贴心地把默认类型从 sessionStorage"纠正"为 globalStorage(src/store.js#L120-L132)
- userData 无法轻易探测,源码干脆"真刀真枪"地添加 behavior 并尝试加载数据,失败即放弃(src/store.js#L137-L161)
- 最后还有内存存储 memory 兜底,保证任何环境下 API 都不会抛错(src/store.js#L250-L287)
这种"层层递进、步步降级"的思路,正是特性检测设计的核心价值所在。
JSON 序列化设计:把对象安全存进浏览器 📦
localStorage 只能存字符串
Web Storage 有一个天然局限:value 只能是字符串。如果直接localStorage.setItem("key", { foo: "bar" }),存进去的会是"[object Object]"。所以 amplify.store 必须自己负责序列化与反序列化。
{ data, expires } 包装格式
看看 src/store.js#L80-L83 的写入逻辑,amplify.store 并没有简单地把数据 stringify 后存进去,而是额外包了一层:
parsed = JSON.stringify({ data: value, // 你的原始数据 expires: options.expires ? now + options.expires : null });这个设计一举两得:
- 用 JSON 序列化,对象、数组、字符串都能存取,天然支持复杂数据结构
- 顺带实现了 expires 过期时间——读取时对比当前时间与 expires,过期数据立即删除(src/store.js#L70-L75)
命名空间前缀与防冲突设计
为了防止与直接操作存储的第三方代码冲突,所有 key 都会加上__amplify__前缀(src/store.js#L29、src/store.js#L66)。遍历整个存储时,也只导出带前缀、由 amplify 管理的数据。此外,源码还专门绕过了 Firefox 4.0 的一个 localStorage 遍历 bug(src/store.js#L41-L46),细节之处足见功力。
userData 的 XML 名称清洗
IE 5-7 的 userData 更加特殊:key 必须是合法的 XML 名称。于是源码用一段正则把所有非法字符替换成短横线(src/store.js#L192-L194)。这也解释了官方文档中提到的"userData 的 key 无法完全保真"这一已知问题。
配额超限:先清理再重试 ⚠️
localStorage 的容量通常只有 5MB 左右,写满时 setItem 会抛异常。amplify.store 的处理策略非常实用(src/store.js#L84-L95):
- 捕获写入异常
- 先执行一次"清扫"——遍历并删除所有已过期的数据
- 再尝试写入一次
- 若仍然失败,抛出 "amplify.store quota exceeded" 错误
userData 后端还多了一层"回滚"保护:失败时先把属性恢复为原值,避免留下半截脏数据(src/store.js#L218-L243)。
总结:这份源码值得你精读 ✅
- 特性检测而非浏览器嗅探,是 amplify.store 跨浏览器兼容的核心思路
- JSON 序列化 + 包装格式,让对象存取与过期时间成为标配能力
- 插件式注册架构,让自定义存储后端变得轻而易举
- 配额超限的清理重试与userData 的回滚保护,展示了成熟库对边界情况的重视
如果你正在设计自己的存储封装,src/store.js 这份源码非常值得逐行研读;想快速上手用法,可以看 demo/store/implicit/demo.js 与 demo/store/sessionstorage/demo.js 两个示例,完整的单元测试则集中在 test/store/unit.js。
【免费下载链接】amplifyAmplifyJS项目地址: https://gitcode.com/gh_mirrors/amp/amplify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
