数据存储
JavaScript 数据存储全解析:从内存到持久化
一、内存中的临时存储
JavaScript 在运行时通过 栈(Stack) 和 堆(Heap) 管理数据:
1. 原始类型(Primitive)
- 存储位置:栈内存(直接存储值)。
- 类型:
undefined
、null
、boolean
、number
、string
、symbol
、bigint
。 - 示例:
const num = 42; // 栈中存储数值 42
const str = "hello"; // 栈中存储字符串 "hello"
2. 引用类型(Reference)
- 存储位置:
- 对象本身存于堆内存。
- 变量在栈中存储指向堆内存的引用地址。
- 类型:
object
、array
、function
、date
等。 - 示例:
const obj = { name: "John" }; // 栈中存储引用地址,堆中存储 { name: "John" }
const arr = [1, 2, 3]; // 栈中存储引用地址,堆中存储数组内容
二、客户端持久化存储
当需要长期保存数据(如跨会话、刷新页面后保留)时,可使用以下方案:
1. Cookie
- 特点:
- 数据随 HTTP 请求发送到服务器(存在安全风险,如 CSRF)。
- 存储上限 4KB。
- 可设置过期时间(
expires
或max-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
- 流程:
- 客户端通过
fetch
或axios
发送请求(如POST /users
)。 - 服务器处理请求并存储数据(如存入数据库)。
- 服务器返回响应(如用户 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
}
}
`
})
});
四、内存优化与性能考量
-
避免内存泄漏:
- 及时释放不再使用的引用(如置为
null
)。 - 避免闭包捕获不必要的变量。
- 及时释放不再使用的引用(如置为
-
大数组/对象处理:
- 使用
TypedArray
(如Float64Array
)存储密集型数据,减少内存占用。
const numbers = new Float64Array(1000); // 预分配 8KB 内存
- 使用
-
IndexedDB 批量操作:
- 避免频繁打开事务,批量处理读写操作:
const transaction = db.transaction(["users"], "readwrite");
const store = transaction.objectStore("users");
users.forEach((user) => store.add(user)); // 批量添加
五、安全性最佳实践
-
敏感数据加密:
- 对 Cookie 中的敏感信息(如会话 ID)使用
HttpOnly
和Secure
标志:document.cookie = "sessionId=123; HttpOnly; Secure";
- 对 Cookie 中的敏感信息(如会话 ID)使用
-
避免 XSS 攻击:
- 不直接将用户输入存入存储,防止脚本注入。
- 读取存储数据时进行转义:
const userInput = localStorage.getItem("comment");
document.getElementById("output").textContent = userInput; // 使用 textContent 而非 innerHTML
-
CORS 与跨域存储:
- 通过
fetch
请求服务器数据时,确保服务器配置了正确的 CORS 头。
- 通过
六、存储方案选择指南
场景 | 推荐方案 | 理由 |
---|---|---|
少量数据,跨会话存储 | LocalStorage | 简单易用,支持字符串化对象 |
会话期间数据(如表单草稿) | SessionStorage | 自动清除,避免冗余存储 |
大量结构化数据 | IndexedDB | 支持事务和复杂查询,存储上限高 |
离线应用 | IndexedDB + Cache API | 结合数据存储和资源缓存 |
实时数据同步 | WebSocket + Redis | 服务器推送 + 高速缓存 |
用户会话管理 | Cookie(HttpOnly) | 自动随请求发送,防止 JS 访问 |
敏感数据 | 服务器端数据库 | 避免客户端直接存储敏感信息 |
七、总结:分层存储策略
现代 JavaScript 应用通常采用多层存储架构:
- 内存层:使用变量、
Map
、Set
快速读写(如缓存高频数据)。 - 客户端层:使用 Web Storage/IndexedDB 实现离线支持和本地缓存。
- 服务器层:使用数据库(关系型/非关系型)实现数据持久化和多用户共享。
根据数据的时效性、大小、安全性需求选择合适的存储方案,是构建高性能、可靠应用的关键。