localForage 完整实战指南:用 localStorage 风格 API 驾驭 IndexedDB、WebSQL 与 localStorage 异步存储
2026/9/20 22:38:57 网站建设 项目流程
  • 前端
  • 缓存抽象

【免费下载链接】localForage

💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.

项目地址:https://gitcode.com/gh_mirrors/lo/localForage
点击查看免费下载

localForage 是一个面向 JavaScript 的快速、简洁的离线存储库,它用一套与localStorage高度一致的简单 API 封装了 IndexedDB、WebSQL 与 localStorage 三种浏览器存储后端,并自动完成异步化与驱动回退。本文以本仓库 README.md 为主体,结合 src/localforage.js 及各驱动源码,完整讲解安装方式、双 API 用法、配置项语义、多实例、自定义驱动与本地开发测试,帮助你在真实项目中安全落地离线数据存储。

什么是 localForage

localForage 的核心设计目标可以用一句话概括:用异步存储(IndexedDB 或 WebSQL)配合简单、localStorage风格的 API,改善 Web 应用的离线体验。它解决了原生浏览器存储的三大痛点:

  • localStorage是同步 API,在主线程上做字符串序列化会阻塞 UI;
  • localStorage容量有限(通常 5MB 左右),且只能存字符串;
  • IndexedDB / WebSQL 虽然强大,但原生 API 冗长、回调繁琐,学习与使用成本高。

localForage 在支持 IndexedDB 或 WebSQL 的浏览器中优先使用异步后端,在没有二者的浏览器(或隐私模式下两者被禁用)中自动回退到 localStorage,从而在不同环境下提供一致的编程体验。

仓库 package.json 显示当前版本为1.10.0,由 Mozilla 维护,采用 Apache-2.0 许可,唯一的运行时依赖是 Promise polyfill 库lie(见 src/utils/promise.js,当全局Promise不存在时自动加载lie/polyfill)。

安装与快速开始

通过 script 标签引入

localForage 设计为"丢一个 JS 文件进页面即可用"。引入构建产物后,全局会暴露localforage对象:

<script src="localforage/dist/localforage.js"></script> <script>localforage.getItem('something', myCallback);</script>

仓库根目录的dist构建产物由 Grunt 任务生成(见 Gruntfile.js 与 package.json 中的build脚本),源码位于 src/localforage.js,入口默认导出的是一个已经初始化好的单例new LocalForage()

通过 npm 安装

npm install localforage

安装后在支持 ES Module / CommonJS 的构建工具中直接import localforage from 'localforage'即可使用。

最小示例

// 写 localforage.setItem('key', 'value'); // 读 localforage.getItem('key').then(function (value) { console.log(value); });

核心 API:Callback 与 Promise 双形态

因为 localForage 走的是异步存储,所以它的 API 天然是异步的;除此之外,调用方式与localStorageAPI 几乎一一对应(getItem/setItem/removeItem/clear/key/keys/length)。它同时提供 Node 风格回调与 Promise 两种形态,官方建议优先使用 Promise

Node 风格回调

localforage.setItem('key', 'value', function (err) { // 如果 err 非 null,说明出错了 localforage.getItem('key', function (err, value) { // 如果 err 非 null,说明出错了;否则 value 就是取到的值 }); });

注意回调签名的统一约定:错误永远在第一个参数,成功数据在第二个参数。

Promise 链式写法

localforage.setItem('key', 'value').then(function () { return localforage.getItem('key'); }).then(function (value) { // 这里拿到 value }).catch(function (err) { // 出错处理 });

async/await 写法

try { const value = await localforage.getItem('somekey'); // 值从离线存储中加载完成后,此代码才会执行 console.log(value); } catch (err) { // 出错处理 console.log(err); }

从源码结构看,这套"双 API"是由 src/utils/executeCallback.js 与 src/utils/executeTwoCallbacks.js 实现的:每个驱动方法内部先构造 Promise,再通过这两个工具把可选的回调接入 Promise 的成功/失败路径,从而让同一份实现同时支持回调和 Promise 两种调用方式。

完整的 API 清单

除读写外,localForage 还提供以下方法(全部支持回调与 Promise 双形态):

方法说明
getItem(key)读取键对应的值,不存在时返回null
setItem(key, value)写入键值,resolve 时返回被写入的值
removeItem(key)删除一个键
clear()清空当前实例的所有数据
length()返回当前 store 中键的数量
key(n)返回第 n 个键(IndexedDB 下用游标advance(n)实现,见 src/drivers/indexeddb.js)
keys()返回所有键的数组
iterate(iterator)遍历所有键值,迭代器返回非undefined值时立即终止遍历
dropInstance(options)按数据库名/存储名删除整个实例(可选方法,见下文自定义驱动一节)

可以存储任意类型:Blob、TypedArray 与普通 JS 对象

与只能存字符串的localStorage不同,localForage 可以存储任意类型:所有能被 JSON 序列化的原生 JS 对象,以及 ArrayBuffer、Blob、TypedArray。即使底层后端是 localStorage,localForage 也会在读写时自动执行JSON.stringify()/JSON.parse(),所以这些类型依然可用——唯一的限制是 localStorage 的容量约束决定了它装不下太多大 Blob。

这一能力在 IndexedDB 后端由 src/drivers/indexeddb.js 原生支持;在 WebSQL / localStorage 后端则由 src/utils/serializer.js 实现。序列化器的工作原理非常值得了解:

  • 普通对象走JSON.stringify/JSON.parse
  • ArrayBuffer 与各 TypedArray(Int8Array、Uint8Array、Uint8ClampedArray、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array)会被转换为 Base64 字符串,并加上__lfsc__:前缀与类型标记(如arbfui08fl32);
  • Blob 会被FileReader读出为 ArrayBuffer 后同样转成带blob类型标记的字符串,type信息通过~~local_forage_type~前缀保留;
  • 反序列化时依据标记还原出原始类型(见 serializer.js 中的deserialize)。

而在 IndexedDB 后端,当浏览器不支持原生 Blob 存储(如 Chrome < 43,详见 indexeddb.js 中的_checkBlobSupport_encodeBlob)时,驱动会先把 Blob 编码为带__local_forage_encoded_blob标记的对象再入库,读取时解码还原,保证跨浏览器行为一致。

配置详解:config() 的六个选项

通过config()方法可以设置数据库信息,可用选项为:drivernamestoreNameversionsizedescription。完整示例(与 README 一致):

localforage.config({ driver : localforage.WEBSQL, // 强制使用 WebSQL;等价于调用 setDriver() name : 'myApp', version : 1.0, size : 4980736, // 数据库大小,单位字节。目前仅 WebSQL 生效。 storeName : 'keyvaluepairs', // 应为字母数字,可带下划线 description : 'some description' });

各选项的语义与实现细节(结合 src/localforage.js 的DefaultConfigconfig()方法):

选项默认值说明
driver['asyncStorage', 'webSQLStorage', 'localStorageWrapper'](按序回退)可传字符串或字符串数组,见下文"驱动选择与回退"一节
name'localforage'数据库名,IndexedDB/WebSQL 中对应真实数据库名;localStorage 后端中作为键前缀的一部分
storeName'keyvaluepairs'存储区名,对应 IndexedDB 的 object store、WebSQL 的数据表;localStorage 后端中拼入键前缀。源码会对该值做清洗:options[i].replace(/\W/g, '_'),即把非字母数字字符统一替换为下划线
version1.0数据库版本号。源码强制校验:typeof options[i] !== 'number'时直接返回Error('Database version must be a number.')
size4980736数据库大小(字节)。默认值刻意设为略低于 5MB,因为这是无需弹窗即可使用的最大配额。注释明确说明"WebSQL-only for now"
description''数据库描述,仅作元信息

使用 config() 的三个关键注意点

  1. 必须在读写之前调用:README 明确强调,必须在调用getItem()setItem()removeItem()clear()key()keys()length()等任何数据操作之前调用config()。源码也印证了这一点——config()内部会检查this._ready,如果实例已经就绪,会直接返回错误"Can't call config() after localforage has been used."
  2. config()兼具 getter 功能:传入字符串时返回对应配置值(config('name')),不传参数时返回整个配置对象。
  3. 传入driver:配置完成后会自动触发setDriver(this._config.driver),等价于手动调用setDriver()

多实例:createInstance

不同业务模块可能需要互相隔离的存储区。createInstance可以创建指向不同 store 的多个 localForage 实例,config()支持的全部选项它都支持:

var store = localforage.createInstance({ name: "nameHere" }); var otherStore = localforage.createInstance({ name: "otherName" }); // 在一个实例上写 key,不影响另一个实例 store.setItem("key", "value"); otherStore.setItem("key", "value2");

从源码看,createInstance(options)就是return new LocalForage(options)(见 src/localforage.js),每个实例拥有独立的_config_dbInfo与驱动状态。有意思的是,IndexedDB 驱动内部通过dbContexts按数据库名维护共享上下文(见 src/drivers/indexeddb.js 的createDbContext):同一数据库名下的多个实例会共享同一个数据库连接,并通过_deferReadiness/_advanceReadiness把每个实例的ready()串成一条就绪链,避免并发打开/升级数据库时的竞争条件;同时每个实例用不同的storeName即可实现互不干扰的逻辑隔离。这也解释了为什么多个实例指向同一数据库时,实例间的初始化会相互等待。

驱动选择与自动回退机制

localForage 内置三个驱动(见 src/localforage.js 的DefaultDrivers),默认按以下顺序尝试:

  1. IndexedDBasyncStorage,src/drivers/indexeddb.js)——容量大、支持任意类型、异步,是首选;
  2. WebSQLwebSQLStorage,src/drivers/websql.js)——基于 SQLite 的异步存储;
  3. localStoragelocalStorageWrapper,src/drivers/localstorage.js)——最后的兜底方案。

驱动可用性由各自的_support检测函数决定,并缓存在DriverSupport中(localforage.supports(driverName)可查询):

  • IndexedDB:见 src/utils/isIndexedDBValid.js。它做了非常细致的检测——排除被伪装成 Safari 的 IE Mobile;对 Safari 要求同时存在原生fetch(用于排除 Safari < 10.1 对 IDB 支持不达标的情况);要求存在indexedDBIDBKeyRange(后者用于排除三星、HTC 等 Android < 4.4 设备的残缺实现);
  • WebSQL:见 src/utils/isWebSQLValid.js,仅判断typeof openDatabase === 'function'
  • localStorage:见 src/utils/isLocalStorageValid.js。

回退逻辑实现在setDriver()中(src/localforage.js):先通过_getSupportedDrivers()过滤出当前环境支持的驱动,再在initDriverdriverPromiseLoop中逐个尝试——前一个驱动初始化失败就 catch 后尝试下一个;全部失败则 reject 并抛出'No available storage method found.'。因此你也可以手动指定驱动顺序,例如:

// 只尝试 IndexedDB 与 localStorage localforage.setDriver([localforage.INDEXEDDB, localforage.LOCALSTORAGE]);

localStorage 后端还有一层额外防护:初始化时通过checkIfLocalStorageThrows()实际写入一个测试键来探测存储是否可用,并专门处理了 Safari 隐私模式下配额为 0 的情况(见 localstorage.js 的_isLocalStorageUsable);写入时捕获QuotaExceededError/NS_ERROR_DOM_QUOTA_REACHED并作为 Promise 拒绝抛出。localStorage 后端的键以name/与(非默认时)storeName/作为前缀(_getKeyPrefix),从而与页面中其他直接使用 localStorage 的代码隔离。

与 RequireJS / 模块化工具搭配使用

localForage 以 UMD 形式发布,可直接与 RequireJS 配合:

define(['localforage'], function(localforage) { // 回调形式: localforage.setItem('mykey', 'myvalue', console.log); // Promise 形式: localforage.setItem('mykey', 'myvalue').then(console.log); });

仓库 examples/require.html 与 examples/require.js 提供了可运行的 RequireJS 示例。

TypeScript 类型支持

仓库自带类型声明 typings/localforage.d.ts(package.jsontypings字段指向它),其中定义了LocalForageOptionsdrivernamestoreNamesizeversiondescription,与config()完全对应)、LocalForageDbMethodsCoregetItemsetItemremoveItemclearlengthkeykeysiterate的泛型签名)以及自定义驱动接口LocalForageDrivertyping-tests/localforage-tests.ts中还有针对这些类型的编译期测试。

导入方式取决于 tsconfig 配置:

  • 若开启了allowSyntheticDefaultImports(TypeScript 1.8+ 支持),推荐:
import localForage from "localforage";
  • 否则使用以下两种之一:
import * as localForage from "localforage"; // 或者,当你的 TypeScript 版本不支持对 UMD 模块使用 ES6 风格导入时: import localForage = require("localforage");

自定义驱动:defineDriver

如果你需要接入新的存储后端(比如 Cordova 插件或其他第三方存储),localForage 提供了defineDriver()注册机制。注册后的驱动对所有 localForage 实例全局共享(源码中的DefinedDrivers容器)。

自定义驱动需要实现一组方法,包括_initStorage与核心数据方法:getItemsetItemremoveItemclearlengthkeykeysiterate(以及可选的dropInstance),并且要提供_driver名称与_support支持检测。defineDriver内部(src/localforage.js)会对驱动做合规校验:

  • _driver必须存在且不与内置驱动重名;
  • 必需方法缺失或不是函数时,拒绝注册并抛出'Custom driver not compliant; see ...#definedriver'错误;
  • 可选方法(如dropInstance)未实现时,会自动注入一个抛错"Method ... is not implemented by the current driver"的占位实现;
  • _support既可以是布尔值,也可以是返回 Promise 的异步检测函数。

测试目录中的 test/dummyStorageDriver.js 就是一个可直接参考的"哑驱动"实现,配合 test.customdriver.js 可以学习驱动注册与使用的最小完整流程。仓库还内置了dropInstance的完整实现示例(见 examples/dropInstance.html)。

框架生态

社区为多个框架提供了基于 localForage 的存储适配层,可以让框架的模型/状态直接落地到离线存储:AngularJS(angular-localForage)、Angular 4+(ngforage)、Backbone(localForage-backbone)、Ember(ember-localforage-adapter)、Vue(vlf)以及 NuxtJS(localforage-module)。如需将自己的驱动加入该列表,可以在仓库 issues 中提交。

本地开发与测试

本地开发需要 node/npm 与 bower。准备工作:

# 全局安装 bower(如未安装): npm install -g bower # 克隆并安装依赖: git clone git@github.com:USERNAME/localForage.git cd localForage npm install bower install

注意:省略 bower 依赖会导致测试失败!因为 localForage 面向浏览器设计,测试用例显式依赖浏览器环境。

运行测试:

npm test # 或直接运行: grunt test

本地测试运行在无头 WebKit(PhantomJS)上,因此需要先安装 PhantomJS;代码同时必须通过 linter(jshint)检查。提交 Pull Request 时,CI(Travis + Sauce Labs)会对 localForage 支持的所有浏览器跑一遍测试矩阵。仓库的测试体系覆盖了:核心 API(test/test.api.js,其中包含iteratedropInstance等方法的用例)、数据类型(test/test.datatypes.js)、驱动选择(test/test.drivers.js)、配置(test/test.config.js)、多实例、Service Workers 与 Web Workers(test/test.serviceworkers.js、test/test.webworkers.js)等场景。

体积与许可

从 1.7.3 版本起,localForage 的打包体积非常可控,使用 gzip 压缩后为应用增加不到 10KB 的负载:

形态体积
minified~29kB
gzipped~8.8kB
brotli~7.8kB

localForage 以 Apache License 2.0 协议分发(见仓库 LICENSE),版权归 Mozilla(2013-2016)及其贡献者所有。若你的项目需要离线优先、跨后端一致的键值存储方案,localForage 提供的这套"简单 API + 自动回退 + 任意类型支持"的组合,是值得优先评估的落地方案。

  • 前端
  • 缓存抽象

【免费下载链接】localForage

💾 Offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API.

项目地址:https://gitcode.com/gh_mirrors/lo/localForage
点击查看免费下载
上一篇:450+终端配色方案,3步生效:iTerm2-Color-Schemes 实用指南
下一篇:AionUi 如何在 Android Termux 中用 Proot Ubuntu 运行 WebUI 模式并实现局域网远程访问

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询