Skip to content

在浏览器中,Web Storage 提供了多种数据存储方式,每种方式适用于不同的场景和需求。以下是浏览器中常见的存储方式及其简介:


浏览器存储 ​

下面给出各类浏览器存储方案的简介及对比,帮助你了解它们各自的特点和适用场景。


1. Web Storage ​

localStorage ​

  • 简介:以键值对方式存储数据,数据持久存在(除非手动清除),即使浏览器关闭后仍然存在。
  • 特点:
    • 持久存储:数据会永久保存在浏览器中,除非显式清除(如手动清理缓存或使用localStorage.clear())。
    • 大小限制:大约 5MB(各浏览器略有不同)。
    • 作用域:同源策略(同协议、同域名、同端口下的页面共享)。
  • API 示例:
javascript
// 存储数据
localStorage.setItem('key', 'value');

// 获取数据
const value = localStorage.getItem('key');

// 删除数据
localStorage.removeItem('key');

// 清空所有数据
localStorage.clear();
  • 应用场景:
    • 存储不敏感的持久数据(如主题偏好、语言设置)。
    • 注意:由于暴露在 JavaScript 中,不适合存储敏感信息(如 Token)。

sessionStorage ​

  • 简介:与 localStorage 类似,但数据仅在当前会话(当前标签页或窗口)内有效,关闭标签页后即清除。
  • 特点:
    • 会话级存储:数据仅在当前浏览器标签页或窗口中有效,关闭页面即失效。
    • 大小限制:大约 5MB。
    • 作用域:同源策略,同标签页/窗口内共享,但不同标签页互不影响。
  • API 示例:
javascript
// 存储数据
sessionStorage.setItem('key', 'value');

// 获取数据
const value = sessionStorage.getItem('key');

// 删除数据
sessionStorage.removeItem('key');

// 清空所有数据
sessionStorage.clear();
  • 应用场景:

    • 存储短期使用的数据(如临时表单数据,会话级状态)。
    • 防止跨标签页共享(如银行系统中的登录状态管理)。

2. Extension Storage ​

  • 简介:浏览器扩展(插件)提供的存储 API,如 Chrome 的 chrome.storage.local 和 chrome.storage.sync。
  • 特点:
    • 异步 API,支持存储扩展专用数据
    • storage.sync 可在设备间同步数据(有配额限制),storage.local 则只在本地存储
  • 典型用途:扩展配置、用户设置、扩展内部状态

3. IndexedDB ​

  • 简介:浏览器内置的 NoSQL 数据库,用于存储大量结构化数据。

  • 特点:

    • 基于事务的 NoSQL 数据库,支持大量结构化数据的存储。
    • 异步 API,避免阻塞主线程。
    • 大小限制:通常为 50MB 以上(取决于浏览器)。
  • API 示例:

    javascript
    // 打开数据库
    const request = indexedDB.open('MyDatabase', 1);
    
    request.onsuccess = (event) => {
      const db = event.target.result;
    
      // 创建事务
      const transaction = db.transaction(['users'], 'readwrite');
      const store = transaction.objectStore('users');
    
      // 添加数据
      store.add({ id: 1, name: 'John Doe' });
    };
  • 应用场景:

    • 存储大量结构化数据(如离线应用、缓存数据、PWA)。
    • 离线模式下的数据存储、文件存储(如 Google Docs 离线版)。

  • 简介:小型键值对数据存储机制,数据会自动随 HTTP 请求发送给服务器。

  • 特点:

    • 大小限制:每个 Cookie 大小约 4KB。
    • 作用域:可设置作用路径和域名,支持跨页面共享。
    • 自动携带:每次请求会自动携带到服务器(除非设置 HttpOnly)。
    • 支持过期时间:可以设置 Expires 或 Max-Age 控制存储时长。
  • API 示例:

javascript
// 设置 Cookie
document.cookie = "username=JohnDoe; expires=Fri, 31 Dec 2025 12:00:00 UTC; path=/";

// 读取 Cookie
console.log(document.cookie);

// 删除 Cookie
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
  • 安全性设置:

    • HttpOnly:禁止 JavaScript 访问(防止 XSS)。
    • Secure:仅通过 HTTPS 传输。
    • SameSite:限制跨站请求携带(防止 CSRF)。
  • 应用场景:

    • 存储会话信息(如 Session ID)。
    • 实现用户偏好设置(如语言选择)。

5. Private State Tokens ​

  • 简介:一种正在探索中的 API/机制,旨在存储用户状态的令牌,但对外提供的是模糊或私有的信息,从而保护用户隐私。
  • 特点:
    • 设计上避免精确跟踪和指纹识别
    • 用于实现无痕但可验证的状态存储,适用于广告转化、欺诈防范等场景
  • 典型用途:隐私保护下的状态保存和跨会话标识,目前仍处于实验或标准制定阶段

6. Interest Groups ​

  • 简介:由浏览器(如在 Privacy Sandbox 提案中)管理的用户兴趣组,网站或广告平台可以建议用户加入某些兴趣组。
  • 特点:
    • 数据在浏览器内部存储,不直接暴露给网站
    • 目的是用于目标广告展示,而不泄露个人详细浏览信息
  • 典型用途:实现隐私友好的广告定向与统计

7. Shared Storage ​

  • 简介:一种提议中的 API,用于在多个来源之间共享汇总数据,但不会泄露用户的个人信息。
  • 特点:
    • 支持跨域或跨会话的聚合数据存储
    • 主要用于广告转化、归因分析等场景
  • 典型用途:跨站点数据聚合与无痕数据共享,目前正处于探索阶段

8. Cache Storage(Service Worker) ​

  • 简介:Service Worker 提供的缓存 API,用于缓存网络请求及响应,实现离线访问和提高加载性能。

  • 特点:

    • 允许通过 Service Worker 缓存 HTTP 请求和响应。
    • 支持离线访问和缓存策略(如 PWA)。
  • API 示例:

    javascript
    // 缓存请求
    caches.open('my-cache').then((cache) => {
      cache.add('/index.html');
    });
    
    // 读取缓存
    caches.match('/index.html').then((response) => {
      if (response) {
        console.log('Cache hit:', response);
      }
    });
  • 应用场景:

    • Progressive Web Apps(PWA)离线缓存。
    • 静态资源的缓存管理(如图片、CSS、JS)。

9. Storage Buckets ​

  • 简介:一种较新的概念,用于将存储空间分区(或“桶化”),以便隔离和管理不同网站或应用的数据。
  • 特点:
    • 每个“桶”相互独立,有助于防止跨站跟踪和数据混用
    • 可能与隐私增强措施相关,例如分区存储数据以减少浏览器指纹信息
  • 典型用途:隐私友好的存储隔离、跨域数据隔离管理,目前正处于实验或提案阶段

总体对比 ​

存储方案存储方式数据持久性数据容量访问方式典型用途安全性/隐私关注点
localStorage键值对持久(手动清除)~5MB同步 API用户偏好、主题设置易受 XSS,适合非敏感数据
sessionStorage键值对会话级(标签页内)~5MB同步 API临时数据、单会话状态隔离性较好,但仅限当前标签页
Extension Storage键值对/对象持久或同步配额较低/中等异步 API扩展配置、状态管理数据仅限扩展内部,安全性由扩展平台保证
IndexedDBNoSQL 数据库持久大量数据异步 API离线应用、复杂数据存储复杂数据存储,需注意数据结构设计
Cookie键值对可配置(会话或持久)~4KB/个同步(自动随请求)会话管理、身份验证、跟踪易受 CSRF,需正确配置安全标记(HttpOnly、Secure)
Private State Tokens令牌设计上持久或短期小(令牌形式)浏览器内部机制隐私保护状态存储、广告转化与欺诈防范目标是保护隐私,防止精确跟踪,目前仍在探索
Interest Groups浏览器管理数据持久(内部管理)小到中浏览器隐式管理广告定向、用户兴趣归类数据不直接暴露,侧重隐私保护下的广告统计
Shared Storage聚合存储设计上持久或聚合视实现而定提议中的 API跨域聚合数据、广告归因隐私友好,数据聚合后不关联个人信息,目前处于提案阶段
Cache Storage请求/响应缓存持久(开发者管理)较大(受配额限制)异步 API静态资源缓存、离线支持、性能优化数据仅限缓存用途,与业务数据分离
Storage Buckets分区存储持久或会话级分区配额浏览器内部管理数据隔离、隐私增强、跨域数据隔离设计上防止跨站跟踪,隔离不同网站数据,目前正处于探索阶段

总结 ​

  • Web Storage(localStorage、sessionStorage) 提供简单的键值存储,适合存储小型、非敏感数据;localStorage 数据持久,而 sessionStorage 仅限当前会话。
  • Extension Storage 专为浏览器扩展设计,支持异步存储和跨设备同步(部分场景)。
  • IndexedDB 适合存储大量、复杂结构数据,是构建离线应用和大数据缓存的首选方案。
  • Cookie 由于每次请求都会自动携带,常用于会话管理与身份验证,但容量有限且安全性依赖配置。
  • Private State Tokens、Interest Groups、Shared Storage、Storage Buckets 等均属于新一代提案或正在探索的 API,旨在在隐私保护下实现数据存储、用户分组与跨站数据聚合,主要针对广告、归因与防跟踪场景。
  • Cache Storage 则专注于资源缓存,提升页面加载和离线体验。

每种存储方式都有其设计初衷和适用场景,开发者应根据数据敏感性、存储量、访问模式和安全要求来选择最合适的方案。

存储方案详解 ​

Web Storage ​

localStorage ​

localStorage 是 Web 浏览器提供的本地存储机制之一,它允许网站将数据以键值对的形式存储在用户的浏览器中,数据即使在页面关闭或浏览器重启后仍然存在,除非被手动清除。


1. localStorage 基本特点 ​

特性详情
存储类型键值对存储(key-value)
数据持久性持久化存储,除非显式清除,否则不会过期
大小限制通常约 5MB(不同浏览器有差异)
作用域同源策略:相同协议 + 域名 + 端口的页面共享数据
自动携带到服务器?❌ 不会随 HTTP 请求自动发送
可否被 JavaScript 访问?✅ 可以,但容易受到 XSS 攻击
适合场景存储非敏感的持久数据(如用户设置、主题、偏好等)

2. localStorage 常用 API ​

方法描述
localStorage.setItem(key, value)存储数据(键值对)。值会被转换为字符串。
localStorage.getItem(key)读取指定 key 的数据。
localStorage.removeItem(key)删除指定 key 的数据。
localStorage.clear()清空当前域下的所有 localStorage 数据。
localStorage.key(index)获取指定索引的 key 名称。
localStorage.length获取当前存储的键值对数量。

3. localStorage 示例代码 ​

a. 基本操作 ​
javascript
// 存储数据
localStorage.setItem('username', 'JohnDoe');

// 获取数据
const user = localStorage.getItem('username');
console.log(user); // 输出: JohnDoe

// 更新数据
localStorage.setItem('username', 'JaneDoe');

// 删除数据
localStorage.removeItem('username');

// 清空所有数据
localStorage.clear();

b. 存储和读取对象(使用 JSON) ​

localStorage 只能存储字符串,若要存储对象或数组,需要使用 JSON.stringify() 和 JSON.parse()。

javascript
// 存储对象
const user = {
  name: "John",
  age: 30,
  role: "admin"
};

localStorage.setItem('user', JSON.stringify(user));

// 读取对象
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser.name); // 输出: John

4. localStorage 的使用场景 ​

  1. 主题/偏好设置:保存用户选择的主题、语言等。
  2. 表单数据缓存:避免刷新页面时丢失表单内容。
  3. 简单的客户端状态管理:如购物车数据、分页设置等。
  4. 缓存数据:缓存一些非敏感的 API 数据减少请求。
  5. SPA(单页面应用):保存 JWT Token(⚠️ 不推荐,见下方安全问题)。

5. localStorage 安全性问题 ​

a. 容易受到 XSS 攻击 ​
  • 问题:localStorage 的数据完全暴露给 JavaScript,如果网站存在 XSS 漏洞,攻击者可以通过注入的恶意代码窃取 localStorage 中的数据。
  • 风险:如果将 敏感数据(如 JWT Token、用户信息)存储在 localStorage 中,可能被窃取。
b. 无法防止 CSRF ​
  • 原因:虽然 localStorage 不会自动随请求发送,但如果使用 JavaScript 手动读取 localStorage 中的 Token 并加到请求头中,仍可能受到 CSRF 攻击。
c. 无加密保护 ​
  • 问题:localStorage 中的数据是明文存储的,任何有权限访问设备的人都可以在浏览器控制台查看数据。

6. localStorage 与其他存储方式对比 ​

存储方式大小限制生命周期可被 JS 访问自动发送到服务器安全性
localStorage~5MB持久(需手动清除)✅❌易受 XSS 攻击
sessionStorage~5MB当前标签页关闭即失效✅❌相对更安全(仅当前标签页)
Cookie~4KB可配置(可持久/会话)✅(非 HttpOnly)✅易受 CSRF,需防护
IndexedDB>50MB持久(需手动清除)✅❌适用于大量数据存储

7. localStorage 最佳实践 ​

  1. 避免存储敏感信息:如用户密码、JWT Token 等。
  2. 使用 JSON 存储复杂数据:使用 JSON.stringify() 和 JSON.parse()。
  3. 清理无用数据:避免长期存储过期数据。
  4. 使用事件监听器同步多标签页数据:
跨标签页数据同步 ​
javascript
// 监听 localStorage 的变化
window.addEventListener('storage', (event) => {
  if (event.key === 'theme') {
    console.log(`主题被更改为: ${event.newValue}`);
  }
});

当在一个标签页中更改了 localStorage 中的数据,其他标签页会通过 storage 事件监听到该变化。


8. localStorage 在真实项目中的使用示例 ​

a. 主题切换示例(浅色/深色模式) ​
html
<button id="toggle-theme">切换主题</button>

<script>
  const btn = document.getElementById('toggle-theme');

  // 检查用户的主题偏好
  const currentTheme = localStorage.getItem('theme') || 'light';
  document.body.className = currentTheme;

  btn.addEventListener('click', () => {
    const newTheme = document.body.className === 'light' ? 'dark' : 'light';
    document.body.className = newTheme;

    // 存储主题偏好
    localStorage.setItem('theme', newTheme);
  });
</script>

<style>
  body.light { background-color: white; color: black; }
  body.dark { background-color: black; color: white; }
</style>

刷新或关闭页面后仍然保持用户上次选择的主题。


9. 什么时候不使用 localStorage? ​

  1. 不存储敏感数据(如 Token、个人身份信息)。
  2. 不用于高频读写操作(如聊天消息、实时数据等)。
  3. 避免存储大规模数据(使用 IndexedDB 替代)。
  4. 对于跨域需求,localStorage 不能跨域共享(使用服务器存储或其他方案)。

✅ 总结 ​

  • localStorage 是简单易用的本地持久化存储方案,适合存储非敏感的持久性数据。
  • 对于安全性要求高的项目,不要将敏感信息存储在 localStorage。
  • sessionStorage、Cookie、IndexedDB 等存储机制可根据具体场景搭配使用。

sessionStorage ​

sessionStorage 是 Web Storage API 的一部分,用于在浏览器中存储数据,具有以下主要特点:


1. 基本特性 ​

  • 会话级存储:
    数据仅在当前浏览器标签页或窗口中有效,一旦标签页关闭,数据即被清除。
    → 适合用于存储临时数据,比如单次会话的表单输入或验证信息。

  • 同源策略:
    仅在同一协议、域名和端口下的页面中共享数据,不同标签页间独立存储数据,即使它们属于同一网站。

  • 容量限制:
    通常约 5MB(与 localStorage 类似,但具体大小因浏览器而异)。

  • 同步 API:
    其操作为同步执行,适合存储少量数据,不适用于大量数据或高频读写场景。


2. 常用 API ​

  • 存储数据:
javascript
sessionStorage.setItem('key', 'value');
  • 读取数据:
javascript
const data = sessionStorage.getItem('key');
  • 删除指定数据:
javascript
sessionStorage.removeItem('key');
  • 清空所有数据:
javascript
sessionStorage.clear();

3. 使用场景 ​

  • 临时状态存储:
    例如,存储用户在单次会话中的操作数据、临时表单内容或一次性令牌,确保数据在标签页关闭后自动清除。

  • 防止跨标签页共享敏感数据:
    如果你希望数据仅限于当前标签页,避免在用户打开多个标签时自动共享,可以使用 sessionStorage。

  • 单页面应用(SPA)中的临时数据:
    在 SPA 中存储当前页面状态、分页信息或其他短期数据。


4. 与 localStorage 的区别 ​

特性sessionStoragelocalStorage
生命周期当前标签页/窗口有效,关闭即失效持久存储,除非主动清除
跨标签页共享不共享,每个标签页独立同源下所有标签页共享
适用场景临时数据、会话状态用户偏好设置、长期缓存数据

5. 注意事项 ​

  • 安全性:
    和 localStorage 一样,sessionStorage 数据也暴露给 JavaScript,因此不建议存储敏感信息。

  • 同步执行:
    操作 sessionStorage 时是同步的,频繁的大数据读写可能会阻塞主线程。


通过合理使用 sessionStorage,可以有效管理单次会话内的临时数据,提供更好的用户体验,同时保证数据不会跨标签页共享。

IndexedDB ​

IndexedDB 是浏览器内置的一种 NoSQL 数据库,用于在客户端存储大量结构化数据。与传统的键值存储(如 localStorage 和 sessionStorage)相比,IndexedDB 提供了更高的存储容量和更丰富的数据操作能力,适合构建离线应用和大数据缓存。


1. 主要特性 ​

  • 异步 API
    IndexedDB 的所有操作都是异步执行的,这意味着它不会阻塞主线程,非常适合处理大量数据或频繁的读写操作。

  • 事务性存储
    支持事务处理,保证数据一致性,允许在一次操作中同时进行多个数据读写操作。

  • 面向对象存储
    数据以对象存储(Object Store)的形式保存,不需要将数据序列化为字符串,能够存储 JavaScript 对象、Blob、File 等类型。

  • 索引支持
    允许为存储的数据创建索引,以便更高效地查询数据。

  • 较大的存储容量
    通常能存储几十 MB 甚至更多数据,具体容量视浏览器实现和用户磁盘空间而定。


2. 基本概念 ​

  • 数据库(Database)
    IndexedDB 存储数据的最高层级单位,一个数据库可以包含多个对象存储。

  • 对象存储(Object Store)
    类似于关系数据库中的表,每个对象存储用于存放具有相似结构的数据。

  • 主键(Key)
    每个存储在对象存储中的数据项都需要一个唯一的键,可以自动生成或由用户指定。

  • 索引(Index)
    为对象存储中的数据创建额外的查找途径,便于基于某些属性进行查询。

  • 事务(Transaction)
    数据操作需要在事务中执行,以保证数据的一致性和完整性。


3. 基本操作示例 ​

下面是一个简单的 IndexedDB 示例,展示如何打开数据库、创建对象存储、添加和读取数据:

javascript
// 打开(或创建)数据库
const request = indexedDB.open('MyDatabase', 1);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  // 创建一个对象存储,指定 keyPath 为 'id'
  const objectStore = db.createObjectStore('users', { keyPath: 'id' });
  
  // 为对象存储创建索引(例如,按姓名查询)
  objectStore.createIndex('name', 'name', { unique: false });
};

request.onsuccess = (event) => {
  const db = event.target.result;
  
  // 开始一个读写事务
  const transaction = db.transaction('users', 'readwrite');
  const store = transaction.objectStore('users');
  
  // 添加数据
  store.add({ id: 1, name: 'Alice', age: 25 });
  store.add({ id: 2, name: 'Bob', age: 30 });
  
  // 读取数据
  const getRequest = store.get(1);
  getRequest.onsuccess = (e) => {
    console.log('获取的数据:', e.target.result);
  };
  
  transaction.oncomplete = () => {
    console.log('事务完成');
  };
};

request.onerror = (event) => {
  console.error('数据库打开失败:', event.target.errorCode);
};

4. 使用场景 ​

  • 离线 Web 应用
    可用于存储大量数据,使应用在离线状态下依然可用(如离线文档、离线表单数据等)。

  • 缓存 API 数据
    在构建单页面应用(SPA)时,可将请求的 API 数据缓存到 IndexedDB,减少网络请求、提高性能。

  • 复杂数据管理
    对于需要存储大量复杂结构数据的应用,如图像、视频、文件、游戏数据等,IndexedDB 提供了更灵活和高效的存储方式。

  • 渐进式 Web 应用(PWA)
    PWA 常利用 IndexedDB 存储资源和数据,以支持离线工作和数据持久化。


5. 优点与挑战 ​

优点挑战或注意事项
支持大量数据存储API 较为复杂,学习曲线较陡
异步操作,不会阻塞主线程浏览器之间实现可能存在差异
支持事务和索引,便于高效查询和数据一致性管理错误处理和版本升级需要仔细设计
能够存储丰富的数据类型,如对象、Blob、File 等调试较为困难,需要借助浏览器开发者工具

6. 总结 ​

IndexedDB 是一种功能强大且灵活的客户端数据库,适用于需要存储大量、复杂数据以及支持离线操作的 Web 应用。

  • 如果你的应用需要存储大量数据或复杂结构数据,并且对数据查询性能和一致性有较高要求,IndexedDB 是一个理想的选择。
  • 然而,由于其 API 的复杂性,在使用前需要投入一定时间学习和设计数据模型。

IndexedDB 与其他存储方案(如 localStorage 或 Cookie)相比,容量更大、功能更丰富,但实现和维护上也更具挑战性。选择合适的存储方案时,应根据应用的具体需求、数据敏感性和开发成本进行权衡。

Cookie 是浏览器存储数据的一种机制,它允许服务器在用户设备上存储小型文本数据,并在随后的请求中自动发送这些数据。Cookie 主要用于维护会话状态、用户身份验证、个性化设置和跟踪用户行为。


1. 基本特性 ​

  • 数据存储形式
    Cookie 以键值对形式存储数据,每个 Cookie 通常只有几个 KB 的大小(每个约 4KB 左右)。

  • 自动发送
    浏览器会在每次向服务器发起请求时自动附带相应域的 Cookie 数据,这对于会话管理和身份验证非常有用。

  • 生命周期

    • 会话 Cookie:默认情况下,Cookie 会在浏览器关闭时失效。
    • 持久 Cookie:可以通过设置 Expires 或 Max-Age 属性,指定 Cookie 的有效期限,使其在浏览器关闭后仍然有效。
  • 作用域控制
    通过设置 Domain 和 Path 属性,可以控制 Cookie 的可访问范围,确保只有特定路径或子域可以读取或发送该 Cookie。


使用 JavaScript 设置 Cookie:

javascript
// 设置一个持久化 Cookie,有效期至 2025 年 12 月 31 日,适用于整个站点
document.cookie = "username=JohnDoe; path=/; expires=Fri, 31 Dec 2025 12:00:00 GMT";

通过 document.cookie 读取 Cookie,返回值为一个包含所有 Cookie 的字符串:

javascript
const cookies = document.cookie;
console.log(cookies); // 可能输出: "username=JohnDoe; session_id=abc123"

删除 Cookie 的方法通常是设置一个过去的过期时间:

javascript
// 删除名为 "username" 的 Cookie
document.cookie = "username=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";

3. 安全性设置 ​

为了提高 Cookie 的安全性,可使用以下属性:

  • HttpOnly
    防止 JavaScript 访问 Cookie,减少 XSS 攻击风险。
    示例:Set-Cookie: session_id=abc123; HttpOnly

  • Secure
    限制 Cookie 仅通过 HTTPS 传输,防止在明文传输中被窃取。
    示例:Set-Cookie: session_id=abc123; Secure

  • SameSite
    控制 Cookie 在跨站请求中是否发送,帮助防御 CSRF 攻击。
    可设置为 Strict、Lax 或 None(若设置为 None,则必须同时使用 Secure)。
    示例:Set-Cookie: session_id=abc123; SameSite=Strict


4. 应用场景 ​

  • 会话管理
    存储 Session ID,帮助服务器识别和维护用户会话状态。

  • 身份验证
    用于实现自动登录、记住用户身份。

  • 个性化设置
    保存用户偏好(如语言、主题等)以便在用户下次访问时自动应用。

  • 用户跟踪与分析
    广告商和分析工具可以使用 Cookie 跟踪用户行为,但这也引发了隐私问题。


5. 总结 ​

  • Cookie 是一种轻量级的数据存储机制,因其自动随请求发送的特性,非常适合用于会话管理和身份验证。
  • 通过设置 HttpOnly、Secure、SameSite 等属性,可以大幅提升 Cookie 的安全性。
  • 与其他 Web 存储机制相比,Cookie 在数据容量上较小,但其与服务器的紧密集成使其成为传统 Web 应用中不可或缺的组件。

如果你对 Cookie 的实现细节、最佳实践或与其他存储方案的深度对比感兴趣,我可以进一步展开说明。

Cache Storage ​

Cache Storage 是由 Service Worker 提供的一种浏览器缓存 API,用于存储 HTTP 请求及其响应数据。它主要用于提升 Web 应用性能和离线体验,能够在应用无网络连接时仍然提供缓存的资源。


1. 主要特性 ​

  • 异步 API
    操作完全异步,不会阻塞主线程,适合存储较大数据和频繁的读写操作。

  • 请求/响应缓存
    专门用于缓存网络请求(如 HTML、CSS、JS、图片等资源)及其响应,开发者可以根据需要决定哪些请求应被缓存。

  • 灵活控制
    开发者可以自定义缓存策略,如缓存优先、网络优先、离线优先等,通过编写 Service Worker 脚本来管理缓存的添加、更新和删除。

  • 持久存储
    缓存数据存储在浏览器中,除非主动删除或缓存失效,否则长期保留,有助于离线访问和快速加载。


2. 使用场景 ​

  • 离线应用支持(PWA)
    缓存网页资源,确保用户在无网络环境下也能正常访问应用的部分功能。

  • 性能优化
    减少重复网络请求,快速加载静态资源,降低延迟,提升用户体验。

  • 动态缓存
    针对用户交互过程中产生的数据,进行缓存和更新,以适应实时性较低的数据展示。


3. 常用 API 与示例 ​

a. 打开/创建缓存 ​

使用 caches.open(cacheName) 方法打开或创建一个命名缓存。

javascript
// 打开或创建一个名为 'my-cache' 的缓存
caches.open('my-cache').then((cache) => {
  // 将指定资源添加到缓存中
  cache.add('/index.html');
});

b. 查找匹配的缓存资源 ​

通过 caches.match(request) 方法可以检索与请求匹配的缓存条目。

javascript
caches.match('/index.html').then((response) => {
  if (response) {
    console.log('从缓存中找到资源', response);
  } else {
    console.log('未找到缓存资源');
  }
});

c. 缓存更新和删除 ​

  • 添加/更新缓存:使用 cache.put(request, response)
  • 删除缓存:使用 caches.delete(cacheName) 删除整个缓存
javascript
// 缓存更新示例
fetch('/new-data.json').then((response) => {
  caches.open('my-cache').then((cache) => {
    cache.put('/new-data.json', response.clone());
  });
});

// 删除指定缓存
caches.delete('my-cache').then((success) => {
  console.log('缓存删除成功:', success);
});

4. 总结 ​

  • Cache Storage 是专为缓存 HTTP 请求和响应而设计的存储机制,主要用于提升页面加载速度和支持离线应用(如 PWA)。
  • 与 localStorage 和 IndexedDB 不同,Cache Storage 主要聚焦于网络资源缓存,通过 Service Worker 管理和更新缓存数据。
  • 适合用来缓存静态资源和部分动态数据,确保在网络状况不佳或离线状态下依然能提供基本功能。

通过合理使用 Cache Storage,开发者可以显著改善 Web 应用的性能和用户体验,尤其在构建渐进式 Web 应用时,它是不可或缺的重要组件。

存储算法 ​

LRU 缓存机制 ​

1. 什么是 LRU 缓存? ​

LRU(Least Recently Used),即 最近最少使用,是一种 缓存淘汰策略,用于在缓存容量不足时,优先移除最久未使用的数据,从而保留最近频繁访问的数据。


2. LRU 的核心思想 ​

  • 缓存大小固定,当缓存满了,需要删除旧数据。
  • 删除最近最少使用的项(即最久未被访问的数据)。
  • 每次访问数据,都会将该数据移动到最前面(最近使用的位置)。

3. LRU 适用于哪些场景? ​

✅ 浏览器缓存(如 Vue keep-alive 缓存的组件)
✅ CPU 缓存(提高数据读取效率)
✅ 数据库缓存(Redis LRU 淘汰策略)
✅ 磁盘缓存(文件系统缓存管理)


4. LRU 实现方式 ​

LRU 常用 哈希表(HashMap)+ 双向链表(Doubly Linked List) 结构来实现:

  1. 哈希表(O(1) 查询) 用于存储缓存数据(键值对)。
  2. 双向链表(O(1) 维护顺序) 记录数据访问顺序:
    • 最近访问的元素放在头部。
    • 淘汰最久未使用的元素,即尾部元素。

关键操作 ​

  • get(key):访问缓存,如果数据存在,将其移动到链表头部。
  • put(key, value):写入缓存:
    • 如果 缓存未满,直接插入头部。
    • 如果 缓存已满,移除尾部元素,然后插入新数据到头部。

5. LRU 代码实现 ​

使用 JavaScript Map ​

ES6 Map 可以维护插入顺序,所以可以用 Map 直接实现 LRU:

js
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
  }

  get(key) {
    if (!this.cache.has(key)) return -1;
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value); // 重新插入到 Map 末尾(最近使用)
    return value;
  }

  put(key, value) {
    if (this.cache.has(key)) this.cache.delete(key); // 先删除旧位置
    this.cache.set(key, value);
    if (this.cache.size > this.capacity) {
      // 删除 Map 第一个元素(最久未使用)
      this.cache.delete(this.cache.keys().next().value);
    }
  }
}

// 测试
const cache = new LRUCache(2);
cache.put(1, "A"); // 缓存 = {1=A}
cache.put(2, "B"); // 缓存 = {1=A, 2=B}
console.log(cache.get(1)); // "A"(访问 1,变为最近使用)=> 缓存 = {2=B, 1=A}
cache.put(3, "C"); // 淘汰 2 => 缓存 = {1=A, 3=C}
console.log(cache.get(2)); // -1(2 已被淘汰)

📌 Map 结构按插入顺序存储数据,delete+set 可维护访问顺序。
📌 淘汰策略:cache.keys().next().value 获取最早的键,并删除它。


使用 HashMap + 双向链表(更高效) ​

如果需要更高效的实现,我们可以使用:

  • HashMap 存储键值对(O(1) 查询)
  • 双向链表 维护访问顺序(O(1) 插入 & 删除)
js
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.map = new Map();
    this.head = {};
    this.tail = {};
    this.head.next = this.tail;
    this.tail.prev = this.head;
  }

  _remove(node) {
    node.prev.next = node.next;
    node.next.prev = node.prev;
  }

  _insert(node) {
    node.next = this.head.next;
    node.prev = this.head;
    this.head.next.prev = node;
    this.head.next = node;
  }

  get(key) {
    if (!this.map.has(key)) return -1;
    const node = this.map.get(key);
    this._remove(node); // 移动到头部
    this._insert(node);
    return node.value;
  }

  put(key, value) {
    if (this.map.has(key)) this._remove(this.map.get(key)); // 删除旧位置

    const newNode = { key, value };
    this._insert(newNode);
    this.map.set(key, newNode);

    if (this.map.size > this.capacity) {
      const lru = this.tail.prev;
      this._remove(lru);
      this.map.delete(lru.key);
    }
  }
}

// 测试
const cache = new LRUCache(2);
cache.put(1, "A"); // {1=A}
cache.put(2, "B"); // {1=A, 2=B}
console.log(cache.get(1)); // "A"(访问后,1 移到最前)=> {2=B, 1=A}
cache.put(3, "C"); // 淘汰 2 => {1=A, 3=C}
console.log(cache.get(2)); // -1(2 已被淘汰)

📌 双向链表 O(1) 维护访问顺序,哈希表 O(1) 查询缓存。
📌 尾部淘汰数据,头部插入最近使用的数据。


6. keep-alive 中的 LRU 机制 ​

keep-alive 结合 max 选项 ​

vue
<keep-alive :max="3">
  <component :is="currentComponent"></component>
</keep-alive>
  • max=3 最多缓存 3 个组件,超过后会淘汰最久未使用的组件。
  • keep-alive 内部使用 LRU 算法来管理缓存组件。

** keep-alive 内部如何实现?** ​

  1. 缓存组件实例(VNode):
    • 维护 cache(哈希表)存储组件。
    • 维护 keys(数组/链表)存储访问顺序。
  2. 访问组件:
    • 如果组件已缓存,将其移动到 keys 头部(表示最近访问)。
  3. 超过 max 限制:
    • 淘汰 keys 尾部组件,并删除 cache 里对应的实例。

评论区

欢迎留言、补充或勘误。

xiaoba.blog