Featured image of post 替换 LocalStorage:动态 IndexedDB 包装器 localForageFeatured image of post 替换 LocalStorage:动态 IndexedDB 包装器 localForage

替换 LocalStorage:动态 IndexedDB 包装器 localForage

通过实施通过 localForage 简化的异步 IndexedDB 引擎,确保大型客户端存储分配。

介绍

客户端存储是现代 Web 应用程序的基本要求 - 离线缓存、用户首选项、草稿数据和会话状态都需要保留在浏览器中。多年来,localStorage 一直是最简单的首选解决方案,但随着应用程序的增长,它的局限性变得令人痛苦。本文对 localStorage、原始 IndexedDB 和 localForage 包装器库进行了比较,为选择正确的存储引擎提供了实用指导。


本地存储的局限性

localStorage 提供了一个简单的同步键值 API — setItem(key, value)getItem(key) — 但它带有硬约束:

约束详情
最大尺寸每个源大约 5 MB(不同浏览器略有不同)
同步API在读/写操作期间阻塞主线程
仅字符串值需要对对象进行手动 JSON 序列化
无索引无法有效查询或过滤存储的数据

在维护大量离线缓存或复杂应用程序状态的单页应用程序中,达到 5 MB 上限是很常见的。此外,阻止渲染的同步写入会降低用户体验,尤其是在慢速设备上。


IndexedDB:强大但复杂

IndexedDB 是浏览器的低级 NoSQL 数据库。它提供:

  • 几乎无限的存储空间(取决于浏览器,通常为数百 MB 到 GB)
  • 完全异步API,不会阻塞UI线程
  • 结构化数据支持——无需序列化的对象、blob 和数组
  • 索引查询用于高效的数据检索

然而,原始 IndexedDB 是出了名的冗长。一个简单的读取操作需要打开连接、创建事务、获取对象存储以及处理成功/错误事件:

const request = indexedDB.open('MyDatabase', 1);
request.onsuccess = (event) => {
  const db = event.target.result;
  const tx = db.transaction('store', 'readonly');
  const store = tx.objectStore('store');
  const get = store.get('myKey');
  get.onsuccess = () => console.log(get.result);
};

这种复杂性使得 IndexedDB 对于简单的键值用例来说很容易出错并且令人不快。


localForage:两全其美

localForage 是一个轻量级 JavaScript 库,它将 IndexedDB(以 WebSQL 和 localStorage 作为后备)包装在受 localStorage 启发的简单异步 API 后面。它会自动选择最佳的可用存储引擎。

npm install localforage

基本用法

import localforage from 'localforage';

// Store a value (supports objects, blobs, arrays)
await localforage.setItem('user', { name: 'Alice', role: 'admin' });

// Retrieve the value
const user = await localforage.getItem('user');
console.log(user.name); // "Alice"

// Remove a key
await localforage.removeItem('user');

// Clear all data
await localforage.clear();

// Get storage length
const len = await localforage.length();

该 API 是基于 Promise 的,因此它可以与 async/await.then() 链无缝协作。

配置

您可以配置驱动程序优先级、数据库名称和存储名称:

localforage.config({
  driver: [localforage.INDEXEDDB, localforage.LOCALSTORAGE],
  name: 'MyApp',
  storeName: 'app_cache',
  version: 1.0,
  description: 'Offline cache for MyApp'
});

回退行为

localForage 按以下顺序检测最佳可用驱动程序:

  1. IndexedDB — 因其容量和异步模型而受到青睐
  2. WebSQL — 已弃用,但在某些浏览器中仍然可用
  3. localStorage — 最后的手段,有 5 MB 的限制

这可确保您的应用程序在任何地方都能工作,同时在存在现代 API 时最大限度地提高存储容量。


代码示例:缓存 API 响应

import localforage from 'localforage';

const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function fetchWithCache(url) {
  const cached = await localforage.getItem(url);
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }
  const response = await fetch(url);
  const data = await response.json();
  await localforage.setItem(url, { data, timestamp: Date.now() });
  return data;
}

此模式减少了网络请求,同时保持 UI 响应能力 — 异步 I/O 永远不会阻止渲染。


何时使用什么

场景推荐存储
简单键值,小数据(< 5 MB)localStorage 或 localForage
大型 JSON blob、离线缓存localForage(IndexedDB 后端)
复杂查询、索引、大型数据集原始索引数据库
跨表同步IndexedDB + 广播频道
临时仅限会话状态会话存储

结论

localStorage 对于真正少量的数据仍然有用,但其同步特性和 5 MB 上限使其不适合现代数据密集型应用程序。 Raw IndexedDB 功能强大,但对于典型的键值场景来说过于复杂。 localForage 通过提供一个干净的、基于承诺的 API 来弥补这一差距,该 API 默认为 IndexedDB,同时可以优雅地降级。对于大多数客户端存储需求,localForage 是务实的选择。