Web应用中的存储方式有哪些?

简介: 本文首发于微信公众号“前端徐徐”,介绍了几种常见的前端数据存储技术:Cookie、Web Storage(包括 localStorage 和 sessionStorage)、IndexedDB、Cache Storage 和 Memory Storage。每种技术的特点和使用场景不同,适用于不同的开发需求。文章详细解释了它们的使用方法、特点和应用场景,并提供了代码示例。

本文首发微信公众号:前端徐徐。

Cookie

Cookie 是存储在用户浏览器中的小型文本文件,用于在客户端和服务器之间传递数据。它是 Web 开发中常用的一种机制,用于在用户访问网站时跟踪和存储有关用户会话、偏好设置、状态等的信息。

使用

设置值

document.cookie = "name=oeschger";
document.cookie = "favorite_food=tripe";
alert(document.cookie);
// 显示:name=oeschger;favorite_food=tripe

读取值

// 得到名为 test2 的 cookie
document.cookie = "test1=Hello";
document.cookie = "test2=World";
const myCookie = document.cookie.replace(/(?:(?:^|.*;\s*)test2\s*\=\s*([^;]*).*$)|^.*$/, "$1");
alert(myCookie);
// 显示:World

特点

Cookie 是 Web 开发中常用的一种机制,用于在客户端(浏览器)和服务器之间传递数据。它具有以下主要特点:

  1. 小型容量
    每个 Cookie 的大小通常有限制,一般为几 KB,通常在 4KB 左右。由于容量有限,不适合存储大量的数据。
  2. 域限制
    Cookie 与特定的域名相关联,只能由该域名下的页面进行读取和修改。这样可以确保 Cookie 的数据仅在特定的网站内有效,不被其他网站访问。
  3. 路径限制
    可以设置 Cookie 的作用路径,限制哪些页面可以访问 Cookie。默认情况下,Cookie 对于设置它的页面以及该页面所在目录下的所有页面都是可见的。
  4. 安全性
    Cookie 中的数据可以被浏览器读取和修改,因此敏感数据应该避免直接存储在 Cookie 中。可以使用加密或其他安全措施来增强 Cookie 的安全性。
  5. 时效性
    Cookie 可以设置过期时间,控制 Cookie 的生命周期。一些 Cookie 是会话 Cookie,会在用户关闭浏览器时被删除,而其他 Cookie 可能会有更长的过期时间。
  6. 数据传递
    通过在 HTTP 请求的头部添加 Cookie,浏览器可以将存储在 Cookie 中的数据发送给服务器。这使得服务器能够根据用户的 Cookie 识别用户、维护用户会话状态、提供个性化体验等。
  7. 持久性
    由于 Cookie 是存储在用户浏览器中的文本文件,它们可以在用户下次访问网站时继续使用。因此,Cookie 可用于在用户访问同一网站时保留数据。
  8. 无状态协议补偿
    HTTP 是一种无状态协议,即服务器无法识别两次请求是否来自同一个用户。通过使用 Cookie,服务器可以在用户浏览器中存储一个唯一的标识符,从而在多个请求之间识别用户,实现会话跟踪。

Web Storage

Web Storage包括localStorage和sessionStorage

使用

// 保存数据到 localStorage
localStorage.setItem('key', 'value');
// 从 localStorage 获取数据
let data = localStorage.getItem('key');
// 从 localStorage 删除保存的数据
localStorage.removeItem('key');
// 从 localStorage 删除所有保存的数据
localStorage.clear();

sessionStorage的使用和localStorage一样

LocalStorage和SessionStorage对比

LocalStorage 和 SessionStorage 都是 Web 存储 API,它们用于在客户端(浏览器)中存储数据。虽然它们在使用和行为上有相似之处,但它们在存储数据的时效性和作用域等方面有一些重要的区别。以下是对比它们的主要差异:

  1. 时效性
  • LocalStorage:存储在 LocalStorage 中的数据没有过期时间,除非用户手动清除或网站代码删除它们。数据会一直保留在客户端,即使浏览器被关闭或电脑重启。
  • SessionStorage:存储在 SessionStorage 中的数据在当前会话期间有效。当用户关闭标签页或浏览器时,会话数据会被清除。会话期间,数据可以在不同页面之间共享。
  1. 作用域
  • LocalStorage:数据在同一个域名下始终有效,不同页面之间可以共享相同的 LocalStorage 数据。
  • SessionStorage:数据在同一个标签页(页面会话)中有效,不同标签页之间无法共享SessionStorage 数据。
  1. 存储大小限制
  • LocalStorage:通常可以存储更多的数据,一般限制在 5MB 到 10MB 之间(不同浏览器可能有所不同)。
  • SessionStorage:一般也限制在 5MB 到 10MB 之间,但由于数据在会话结束时被清除,所以通常会拥有与 LocalStorage 相同的存储空间。
  1. 数据共享与隔离
  • LocalStorage:由于数据在同一个域名下共享,可能会导致不同页面之间共享相同的数据。这在某些场景下是有用的,但也需要小心管理以避免数据冲突。
  • SessionStorage:数据只在当前会话期间有效,不同标签页之间无法共享数据。这使得SessionStorage 在某些场景下更适合临时保存和隔离数据。

应该根据具体的需求来选择使用 LocalStorage 还是 SessionStorage。如果需要长期保存数据或数据在不同页面间共享,可以使用 LocalStorage。如果只需要在单个会话期间保存临时数据,并且不需要跨页面共享数据,那么 SessionStorage 是更合适的选择。

IndexedDB

IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。

使用

// 打开或创建名为 "myDatabase" 的数据库
const request = indexedDB.open('myDatabase', 1);
// 数据库创建或升级时触发
request.onupgradeneeded = event => {
  const db = event.target.result;
  // 创建一个名为 "users" 的对象存储空间(相当于数据库表)
  const usersStore = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true });
  // 定义需要存储的数据结构
  usersStore.createIndex('name', 'name', { unique: false });
  usersStore.createIndex('email', 'email', { unique: true });
};
// 数据库打开成功后触发
request.onsuccess = event => {
  const db = event.target.result;
  // 获取事务并访问对象存储空间
  const transaction = db.transaction('users', 'readwrite');
  const usersStore = transaction.objectStore('users');
  // 存储数据
  usersStore.add({ name: 'John Doe', email: 'john@example.com' });
  usersStore.add({ name: 'Alice Smith', email: 'alice@example.com' });
  // 查询数据
  const emailIndex = usersStore.index('email');
  const request = emailIndex.get('john@example.com');
  request.onsuccess = event => {
    const user = event.target.result;
    if (user) {
      console.log(user); // { id: 1, name: 'John Doe', email: 'john@example.com' }
    } else {
      console.log('User not found.');
    }
  };
};
// 处理数据库打开失败
request.onerror = event => {
  console.error('Error opening database:', event.target.error);
};

这只是 IndexedDB 的简单示例,它还支持更复杂的查询、索引、范围查询等功能,可以满足更复杂的数据存储需求。IndexedDB 是一种强大的客户端存储解决方案,特别适合需要离线访问、大量数据存储和复杂查询的 Web 应用。这里就不详细展开来讲,如果想了解更多可以去MDN网站查看它的使用及底层原理。

特点

  1. 容量较大
    IndexedDB 可以存储大量数据,通常限制在 50MB 到数百 MB 之间(不同浏览器可能有所不同),远远超过传统的本地存储(如 LocalStorage)的容量限制。
  2. 异步 API
    IndexedDB API 是异步的,它使用 Promise 或类似的异步机制来处理数据的存储和检索。这样可以避免阻塞主线程,提高应用程序的响应性能。
  3. 事务支持
    IndexedDB 支持事务概念,可以在一个事务中执行多个数据操作,保证数据的一致性和完整性。事务可确保所有数据操作都要么全部成功,要么全部失败,以避免部分数据操作导致的数据不一致。
  4. 复杂查询
    IndexedDB 支持多种查询方式,可以通过索引来高效地检索数据。你可以创建索引以提高查询性能,并使用游标或范围查询等方式查询数据。
  5. 支持多个对象存储空间
    IndexedDB 允许在一个数据库中创建多个对象存储空间(类似于数据库表),每个对象存储空间可以存储不同类型的数据。这样可以更好地组织数据,使数据模型更灵活。
  6. 跨标签页和浏览器窗口支持
    与 LocalStorage 不同,IndexedDB 支持多个标签页或浏览器窗口之间共享数据。这使得 IndexedDB 更适合在复杂的 Web 应用中共享数据。
  7. 数据安全性
    IndexedDB 中的数据是相对安全的,因为数据只能被存储在用户的本地设备上,不会被发送到服务器,也不会受到跨站点请求伪造(CSRF)等网络攻击的影响。

Cache Storage

Cache Storage 是浏览器提供的一种 API,它是用于缓存资源文件的存储方式,在 PWA(Progressive Web App)中,Cache Storage 是一个重要的组成部分,它允许开发者将网站所需的资源(例如 HTML、CSS、JavaScript、图像等)保存在客户端的缓存中,以便在离线时仍然能够访问网站,并提供更快的加载速度和更好的用户体验。

使用

// 在 Service Worker 中缓存资源文件
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open('my-cache').then(cache => {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles.css',
        '/script.js',
        '/images/logo.png'
        // 可以添加其他需要缓存的资源文件
      ]);
    })
  );
});
// 拦截网络请求并从缓存中响应资源
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      // 如果缓存中有匹配的资源,则直接返回缓存中的响应
      if (response) {
        return response;
      }
      // 否则,从网络中获取资源,并将响应缓存起来
      return fetch(event.request).then(response => {
        // 使用 clone() 方法,因为 response 是只能使用一次的对象
        const clonedResponse = response.clone();
        caches.open('my-cache').then(cache => {
          cache.put(event.request, clonedResponse);
        });
        return response;
      });
    })
  );
});

上述代码是一个简单的 Service Worker 脚本,它在安装阶段将指定的资源文件缓存到名为 "my-cache" 的 Cache Storage 中。然后,在网络请求发生时,它会先检查缓存中是否存在匹配的资源,如果有,则直接返回缓存中的响应;如果没有,则从网络获取资源,并将响应缓存起来,以便以后离线时可以使用。

⚠️注意事项:Cache Storage 的使用需要配合 Service Worker,因为它们通常用于离线缓存和拦截网络请求

特点

  1. 离线访问
    Cache Storage 允许将网站所需的资源(如 HTML、CSS、JavaScript、图像等)缓存到客户端的缓存中,使得网站在离线时仍然可以访问这些资源。这为 PWA(Progressive Web App)提供了离线访问的能力,提升了用户体验。
  2. 快速加载
    通过缓存资源,可以实现更快的加载速度。当用户再次访问网站时,资源可以从缓存中直接加载,无需再次从服务器请求,减少了网络延迟和服务器负担,提高了页面的加载性能。
  3. 多级缓存
    Cache Storage 支持多级缓存,可以将资源分为不同的缓存级别,如缓存优先级高的资源和缓存优先级低的资源。这样可以更灵活地控制缓存策略,确保常用的资源总是可以快速地被访问。
  4. 缓存策略
    开发者可以通过控制 Service Worker 的缓存策略来定义资源的缓存行为。例如,可以指定资源的过期时间,强制重新请求最新的资源,或者使用新的资源更新旧的缓存等。
  5. 网络拦截
    通过 Service Worker,Cache Storage 可以拦截网络请求,并决定是否从缓存中提供资源,或者通过网络请求最新的资源。这为开发者提供了更大的灵活性和控制权。
  6. 跨会话缓存
    Cache Storage 中的缓存数据不受会话限制,即使用户关闭浏览器或重新启动设备,缓存数据仍然可以保留,从而使得缓存的资源可以在多个会话中共享,提供更持久的缓存效果。
  7. 资源管理
    开发者可以根据具体需求随时添加、更新或删除缓存中的资源,从而实现资源的动态管理和更新。

Memory Storage

Memory Storage(内存中存储数据)通常用于简单的状态管理,特别是在一些小型应用或简单的组件之间共享状态数据。内存中存储数据不涉及持久化,数据只在内存中存在,一旦页面刷新或关闭,数据将丢失。这使得它适用于临时存储数据或共享状态,但不适用于需要长期保持数据的场景。

使用

常见的状态管理,比如Vue里面的datareact中的useState。这里就不详细展开了,在我们日常开发中基本都是随处可见的内存存储数据的方式。

特点

  1. 临时存储
    Memory Storage 仅在当前会话期间有效,一旦用户关闭浏览器标签或窗口,数据将丢失。它适用于临时存储数据,例如在单个会话中共享状态或传递临时信息。
  2. 数据在内存中
    数据存储在浏览器的内存中,不会发送到服务器,因此不涉及网络请求。这使得读取和写入数据的速度非常快。
  3. 数据的生命周期与页面一致
    Memory Storage 的生命周期与网页的生命周期一致。当页面刷新或关闭时,存储在 Memory Storage 中的数据将被清除,不会被保留。
  4. 轻量级
    Memory Storage 不会像持久化存储(如 LocalStorage 或 IndexedDB)那样占用大量的磁盘空间,因为数据仅存储在浏览器的内存中。
  5. 不支持跨标签页和浏览器窗口共享数据
    每个标签页或浏览器窗口都有自己的独立的 Memory Storage,它们之间无法直接共享数据。如果需要在多个标签页或浏览器窗口之间共享数据,可以考虑使用其他持久化存储方案。
  6. 适用于简单状态管理
    Memory Storage 在某些场景下适用于简单的状态管理,特别是在小型应用或组件中共享状态数据。然而,对于复杂的状态管理需求,应该使用专业的状态管理工具,如 Redux 或 Vuex,以及持久化存储方案。

应用场景总结

  1. Cookie: 适合用于在客户端和服务器之间传递少量的用户身份信息、会话信息或用户偏好设置等。
  2. LocalStorage: 适合存储少量的键值对数据,例如用户配置、主题设置、用户喜好等。也可用于缓存一些静态资源,以提高页面加载速度。
  3. SessionStorage: 适合存储会话期间需要保留的数据,例如表单数据、临时状态等。仅在当前会话中有效,关闭页面后数据将丢失。
  4. IndexedDB: 适合存储大量的结构化数据,适用于需要离线访问和复杂查询的 Web 应用。适合较复杂的数据操作和数据查询需求。
  5. Cache Storage: 适合用于 PWA 中的离线访问和资源缓存,提供更快的页面加载速度和离线使用体验。
  6. Memory Storage: 适合简单的状态管理,特别是在小型应用或简单组件中共享状态数据,用于临时存储数据。

综合考虑存储容量、持久性、应用场景等因素,选择合适的存储方式对于开发前端应用至关重要。在实际应用中,可能会结合使用不同的存储方式,以满足复杂的数据管理需求。对于复杂的状态管理需求,可以考虑使用专业的状态管理工具,如 Redux(用于 React)或 Vuex(用于 Vue)。

相关文章
|
2天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1529 4
|
17小时前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
29天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
6天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
521 20
|
2天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
186 2
|
9天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
21天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
9天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
480 5
|
8天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
317 2
|
5天前
|
XML 安全 Java
【Maven】依赖管理,Maven仓库,Maven核心功能
【Maven】依赖管理,Maven仓库,Maven核心功能
196 2