这篇文章发布于 2026年09月3日,星期四,17:39,归类于 JS API。 阅读 86 次, 今日 85 次 没有评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12379
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
一、Web本地化存储
本来想巴拉巴拉说一堆东西的。
可一想,现在都是快餐时代 + AI时代了,耐心缺失 + 学习热情缺失。
连孙晨宇的小作文都只是看个大概,还指望那些洋洋洒洒的技术内容有人认真拜读,异想天开了。
所以,我决定了,直接一个表格一把梭。
| 存储方案 | 存储容量 | 持久化特性 | 存储类型 | 运行线程 | 主要适合场景 | 缺点 & 局限 |
|---|---|---|---|---|---|---|
| Cookie | 约 4KB | 可设置 expires 持久;默认会话级关闭标签失效 | 仅字符串;每次 http 请求自动带到后端 | 主线程 | 服务端读取标识、会话 token、简单埋点标记 | 容量极小;请求头携带增加网络开销;只能存字符串;易被 XSS 窃取 |
| localStorage | 5‑10MB | 持久,手动删除 / 清站点数据才消失 | 仅字符串 | 只能主线程 | 简单小 key‑value 配置、简单用户偏好设置 | 只能字符串;同步读写,大数据会阻塞主线程;容量有限 |
| sessionStorage | 5‑10MB | 标签页会话级别,关闭当前标签立刻清空 | 仅字符串 | 只能主线程 | 单标签临时状态缓存,表单临时草稿 | 多 tab 之间隔离;关标签数据全部丢失;同步 API 阻塞;不能存二进制 |
| IndexedDB | 一般几十 MB~ 浏览器配额上限 | 持久,清站点数据删除 | String、Blob、ArrayBuffer、Object 等,支持二进制 | 主线程 + WebWorker | 结构化数据、Blob 资源缓存(字体 / 图片),需要索引查询的业务 | API 繁琐;大 Blob 存取存在结构化克隆内存开销;不能像文件一样 append 追加 |
| OPFS (getDirectory) |
受 origin 总配额限制 (可几十‑几百 MB) | 持久,清站点数据删除 | ArrayBuffer、Uint8Array,真实文件句柄 | 主线程 (异步 API);Worker 可高性能同步句柄 | 大二进制文件缓存(字体、音视频片段、本地草稿文件)、字节级随机读写、追加写入 | 兼容性差;无查询索引能力,就是文件系统;用户看不到物理文件;不能跨 origin 共享文件 |
一直到IndexedDB这里的存储方式,想必大多数前端都有所了解,而最后出现的OPFS(Origin private file system)知道的人就不多了。
这是一类类似于 SQLite 数据库的文件系统,通过 navigator.storage.getDirectory() 方法返回一个 FileSystemDirectoryHandle,继而对文件进行读写追加等管理。
一例胜千言,话不多说,直接上案例。
二、OPFS与完整中文字体案例
您可以狠狠地点击这里:OPFS 与中文字体持久存储demo
首次进入走请求:

之后每次进来,就是秒开了,开销只存在第一次开发场景。

此demo是混元4模型生成的,AI还真好使,以前弄个demo都要手搓,时间要花很多倍,现在只需要提出诉求,然后自己稍微改改就好了。
在过去的Web开发中,引入完整的中文字体是不现实的,因为字体都很大,会严重拖慢页面的加载速度。
可现在,类似于font-spider这样的字体动态生成工具的必要性已经大不如从前了。
很简单,一个完整的中文字体平均大小6M左右,如果转为woff2字体合适,可以降低到3M左右。
3M的文件大小是什么概念呢?
也就是一个开屏广告的大小,甚至不如一个GIF表情包的大小。
而字体文件是没有任何所谓的迭代概念的。
字体一旦设计出来,几乎就没有改动。
所以,只要有一个可靠的存储方案,中文字体完全就可以全局引入。
具体为:
- 第一次加载走请求,按照现在的网速,可能几秒钟就结束了,然后存储在本地。
- 下一次加载的时候,直接从本地读取,用户几乎无感知。
问题来了,该使用什么本地存储技术呢?
在之前,IndexedDB是不二选择,现在有了OPFS,IndexedDB就没用任何使用的必要了,原因很简单:
OPFS的性能太高了,代码也简单太多了。
代码
性能大家可能感觉不出来,但是代码一眼可见,下面展示的就是读写和字体应用的核心代码。
// ① 打开浏览器私有文件系统(OPFS)根目录
const root = await navigator.storage.getDirectory();
const KEY = 'key-font-tencent';
// ② 读取:不传 create,文件不存在时会抛 NotFoundError
let file;
try {
const handle = await root.getFileHandle(KEY);
file = await handle.getFile(); // 二次进入:零网络请求
} catch {
// ③ 写入:响应流管道直连落盘,大字体文件不会整体驻留内存
const res = await fetch('./tencent.woff2');
const handle = await root.getFileHandle(KEY, { create: true });
await res.body.pipeTo(await handle.createWritable());
file = await handle.getFile();
}
// ④ 注册为自定义字体,之后即可用 font-family: Tencent
const face = new FontFace('Tencent', await file.arrayBuffer());
document.fonts.add(await face.load());
可以看到,无论是文件的读还是写,就是两行代码的事情。
而IndexedDB的语法就复杂多了,理解成本也高,往往需要借助第三方组件简化使用。
所以,眼下,对于大文件的本次持久化存储,别再使用IndexedDB,使用getDirectory()吧。
除非,你需要存储的东西是结构化的数据,或者要兼容很多陈旧的设备,否则,IndexedDB没有任何优势。
三、和File System Access API的区别
origin private file system (OPFS)属于File System API的一部分,那它和之前介绍过的File System Access API又是什么关系呢?
一句话:
OPFS是File System API的核心能力,而File System Access API是构建在 File System API 之上的上层扩展。
OPFS可以看成是文件系统API的亲儿子,而FSAA可以看成是文件系统API的外戚。
前者被所有现代浏览器支持,后者目前仅Chrome支持,也就是之前介绍过的showOpenFilePicker()手动触发本地文件选择的方法。
详见此文:“不使用file类型input也能触发文件上传”
看了下,是5年前的文章,妈呀,5年过去了,Safari和Firefox浏览器都还没支持File System Access API,估计以后也难了。
还是通过表格对比下吧,比叽里咕噜说一堆话有用多了。
| 对比维度 | OPFS 源私有文件系统 | File System Access API(FSA) |
|---|---|---|
| 文件位置 | 浏览器内部沙盒,用户资源管理器不可见;磁盘真实存在,但路径不对外暴露 | 操作系统真实磁盘,用户看得见(桌面、文档等) |
| 触发方式 | 直接调用 navigator.storage.getDirectory(),无需弹窗、无需用户点击手势,后台静默读写 |
必须用户主动点击手势触发文件选择弹窗,用户手动挑选文件 / 文件夹,不能后台静默打开本地文件 |
| 权限模型 | Origin 隔离;无弹窗授权;受浏览器存储配额管理;清除站点数据全部销毁 | 操作系统文件权限;句柄可保存,但刷新页面后读写权限会失效,需要重新申请权限;用户可在浏览器设置撤销权限 |
| 配额限制 | 和 IndexedDB / CacheStorage 共享 origin 总配额,可用navigator.storage.estimate()查询;磁盘满抛配额溢出错误 |
不受浏览器站点配额限制,受操作系统磁盘大小限制;直接读写用户磁盘 |
| 线程能力 | 主线程异步 API;WebWorker 支持高性能同步句柄 createSyncAccessHandle(),支持字节随机读写 |
全部接口为异步 Promise;Worker 不能调用 Picker 弹窗 API |
| 数据销毁 | 需要OPFS API删除,或存储不足浏览器自动删除(一般不会) | 文件永久保存在用户磁盘;网页销毁不会删除磁盘文件,需要网页主动调用 remove |
| 典型使用场景 | Web 应用内部缓存:缓存字体、离线资源、本地草稿、WebAssembly‑SQLite 数据库,应用内部私有数据 | Web 编辑器打开 / 保存用户本地文档;webIDE 读写用户本地项目文件夹,用户主动管理的文件 |
| 浏览器兼容性 | ✓ | Chrome86+ only |
四、再说点什么
接下来的内容大家悄悄传播,千万不要让厂子的法务知道,不然又要让我删除了。
本月开始,Token额度大降,从之前每人6K,降到500元,其中还有120元的占位费,也就是灵活支配的额度只有380元。
超过的,要走报销。
我这人最怕麻烦了,一想到报销就算了,所以,眼下只能省着点用了。
不过之前用得也不多,平均10%多一点。
窍门就在于让AI担任填充角色,然后多花时间阅读代码,给AI指明路径与策略,就会节约大量AI的思考,就省钱了。
然后现在国产模型的能力也相当不错,日常需求非常够用了。
所以,一个月500元足够了。
本月到现在,我一分钱还没花呢?

窍门在哪里?
很简单,混元模型最近免费,哈哈哈,羊毛不薅白不薅。
还有,厂子的前端技术中心的组织架构好像没了。
大家都分散到各个业务线了。
我的组织架构也变了,从以前的XXX换到XXX了。
果然,时代变了。
好了,不能再多透露了,我说完了。

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12379
(本篇完)
- 不使用file类型input也能触发文件上传 (0.298)
- HTML5 indexedDB前端本地存储数据库实例教程 (0.252)
- 了解woff2字体及转换 (0.168)
- JS FontFace API字体加载失败或完毕的检测 (0.168)
- HTML5 localStorage本地存储实际应用举例 (0.147)
- 醒醒,该使用CookieStore新建和管理cookie了 (0.147)
- 理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型 (0.109)
- jQuery-马化腾产品设计与用户体验的一些技术实现 (0.084)
- 热门:响应图片(Responsive Images)技术简介 (0.084)
- 小tip: 使用meta实现页面的定时刷新或跳转 (0.084)
- 今天才知道,Web网页也能阻止息屏了 (RANDOM - 0.072)