Skip to main content

数据存储

JavaScript 数据存储全解析:从内存到持久化

一、内存中的临时存储

JavaScript 在运行时通过 栈(Stack)堆(Heap) 管理数据:

1. 原始类型(Primitive)

  • 存储位置:栈内存(直接存储值)。
  • 类型undefinednullbooleannumberstringsymbolbigint
  • 示例
    const num = 42;        // 栈中存储数值 42
    const str = "hello"; // 栈中存储字符串 "hello"

2. 引用类型(Reference)

  • 存储位置
    • 对象本身存于堆内存。
    • 变量在栈中存储指向堆内存的引用地址。
  • 类型objectarrayfunctiondate 等。
  • 示例
    const obj = { name: "John" };  // 栈中存储引用地址,堆中存储 { name: "John" }
    const arr = [1, 2, 3]; // 栈中存储引用地址,堆中存储数组内容

二、客户端持久化存储

当需要长期保存数据(如跨会话、刷新页面后保留)时,可使用以下方案:

  • 特点
    • 数据随 HTTP 请求发送到服务器(存在安全风险,如 CSRF)。
    • 存储上限 4KB
    • 可设置过期时间(expiresmax-age)。
  • 场景
    • 会话管理(如登录状态)、用户偏好(如主题颜色)。
  • 示例
    // 设置 Cookie
    document.cookie = "username=John; expires=Thu, 31 Dec 2025 23:59:59 GMT; path=/";

    // 读取 Cookie
    function getCookie(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    return parts.length === 2 ? parts.pop().split(';').shift() : null;
    }

2. Web Storage(LocalStorage & SessionStorage)

  • 特点
    • LocalStorage:永久存储(除非手动清除),上限约 5-10MB
    • SessionStorage:会话期间有效(页面关闭后清除),上限相同。
    • 仅在客户端存储,不随请求发送。
    • 存储类型为字符串,需手动序列化/反序列化对象。
  • 场景
    • 缓存不敏感数据(如表单草稿、应用配置)。
  • 示例
    // 存储对象
    localStorage.setItem("user", JSON.stringify({ name: "John", age: 30 }));

    // 读取对象
    const user = JSON.parse(localStorage.getItem("user"));

    // 删除项
    localStorage.removeItem("user");

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

3. IndexedDB

  • 特点
    • 异步键值对存储,支持事务和版本控制。
    • 存储上限约 250MB 或更多(取决于浏览器和设备)。
    • 可存储复杂数据类型(如文件、二进制数据)。
  • 场景
    • 离线应用(如 PWA)、大量数据存储(如图库、聊天记录)。
  • 示例
    const request = indexedDB.open("myDatabase", 1);

    request.onupgradeneeded = (event) => {
    const db = event.target.result;
    db.createObjectStore("users", { keyPath: "id" });
    };

    request.onsuccess = (event) => {
    const db = event.target.result;
    const transaction = db.transaction(["users"], "readwrite");
    transaction.objectStore("users").add({ id: 1, name: "John" });
    };

4. Cache API(Service Worker 缓存)

  • 特点
    • 专门用于缓存 HTTP 请求和响应。
    • 与 Service Worker 配合实现离线支持。
  • 场景
    • 缓存静态资源(如 CSS、JS、图片)。
  • 示例
    self.addEventListener('fetch', (event) => {
    event.respondWith(
    caches.match(event.request)
    .then((response) => response || fetch(event.request))
    );
    });

三、服务器端存储(与 JS 交互)

当需要跨设备或多用户共享数据时,可通过 API 与服务器交互:

1. REST API

  • 流程
    1. 客户端通过 fetchaxios 发送请求(如 POST /users)。
    2. 服务器处理请求并存储数据(如存入数据库)。
    3. 服务器返回响应(如用户 ID)。
  • 示例
    // 发送数据到服务器
    fetch("/api/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name: "John", age: 30 })
    })
    .then((response) => response.json())
    .then((data) => console.log("用户ID:", data.id));

2. GraphQL

  • 特点
    • 客户端精确控制需要的数据结构。
    • 单一端点处理所有请求,减少冗余数据传输。
  • 示例
    // 发送 GraphQL 查询
    fetch("/graphql", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
    query: `
    query {
    user(id: "1") {
    name
    age
    }
    }
    `
    })
    });

四、内存优化与性能考量

  1. 避免内存泄漏

    • 及时释放不再使用的引用(如置为 null)。
    • 避免闭包捕获不必要的变量。
  2. 大数组/对象处理

    • 使用 TypedArray(如 Float64Array)存储密集型数据,减少内存占用。
    const numbers = new Float64Array(1000); // 预分配 8KB 内存
  3. IndexedDB 批量操作

    • 避免频繁打开事务,批量处理读写操作:
    const transaction = db.transaction(["users"], "readwrite");
    const store = transaction.objectStore("users");

    users.forEach((user) => store.add(user)); // 批量添加

五、安全性最佳实践

  1. 敏感数据加密

    • 对 Cookie 中的敏感信息(如会话 ID)使用 HttpOnlySecure 标志:
      document.cookie = "sessionId=123; HttpOnly; Secure";
  2. 避免 XSS 攻击

    • 不直接将用户输入存入存储,防止脚本注入。
    • 读取存储数据时进行转义:
      const userInput = localStorage.getItem("comment");
      document.getElementById("output").textContent = userInput; // 使用 textContent 而非 innerHTML
  3. CORS 与跨域存储

    • 通过 fetch 请求服务器数据时,确保服务器配置了正确的 CORS 头。

六、存储方案选择指南

场景推荐方案理由
少量数据,跨会话存储LocalStorage简单易用,支持字符串化对象
会话期间数据(如表单草稿)SessionStorage自动清除,避免冗余存储
大量结构化数据IndexedDB支持事务和复杂查询,存储上限高
离线应用IndexedDB + Cache API结合数据存储和资源缓存
实时数据同步WebSocket + Redis服务器推送 + 高速缓存
用户会话管理Cookie(HttpOnly)自动随请求发送,防止 JS 访问
敏感数据服务器端数据库避免客户端直接存储敏感信息

七、总结:分层存储策略

现代 JavaScript 应用通常采用多层存储架构

  1. 内存层:使用变量、MapSet 快速读写(如缓存高频数据)。
  2. 客户端层:使用 Web Storage/IndexedDB 实现离线支持和本地缓存。
  3. 服务器层:使用数据库(关系型/非关系型)实现数据持久化和多用户共享。

根据数据的时效性、大小、安全性需求选择合适的存储方案,是构建高性能、可靠应用的关键。