浏览器缓存--阅读笔记

一、浏览器缓存

  • 强缓存:浏览器在请求资源时,会根据请求的http header判断是否是强缓存,如果是强缓存,会直接从浏览器中读取资源,不会向服务器发送请求;

  • 协商缓存:如果不是强缓存,浏览器就发送请求到服务器,通过服务器端依据请求资源的http header看是否是协商缓存,如果是浏览器就会将这个请求返回,但是返回内容中没有数据,而是告诉客户端可以直接从缓存中加载资源,最终浏览器从自己的缓存中加载资源;【HTTP返回状态码304】

  • 共同点:都是从浏览器端加载资源,而不从服务器端;

  • 区别:强缓存不会发送请求到服务器,协商缓存会发送请求到服务器;

    如果请求也不是协商缓存,那么浏览器直接获取到服务器端的资源并加载。


二、强缓存

 京东首页强缓存如下图中红色部分,强缓存的http返回状态码是200,size显示from cache。

京东首页请求

  • 强缓存是通过http header中的Expires和Cache-Control实现的,如下图所示:两个对应的是资源在客户端缓存的有效期。

强缓存请求头

  • Expires是http1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器端返回,用GMT格式的字符串表示。
    它的缓存原理:

    1、浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在response的header上加Expires;
    2、浏览器接收到这个资源后,会把这个资源和它素有的response header一起缓存下来(缓存命中的请求返回的header并不是来自服务端,而是来自之前缓存的header);
    3、浏览器再请求这个资源时,先从缓存中寻找,找到这个资源后,拿出它的Expires跟当前请求时间比较,如果请求时间在指定时间之前,就会命中强缓存,否则不行;
    4、如果没有命中缓存,浏览器会从服务端重新加载资源并将Expires header记录下来。

  • Expires是较老的强缓存管理header,由于是返回绝对时间,在服务端和客户端时间相差较大时,缓存管理容易出现问题,所以在http1.1的时候提出了一个新的缓存管理header即Cache-Control,这是一个相对时间,用数值来表示。
    它的缓存原理:
    1、浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在response的header上加Cache-Control ;
    2、浏览器接收到这个资源后,会把这个资源和它素有的response header一起缓存下来(缓存命中的请求返回的header并不是来自服务端,而是来自之前缓存的header);
    3、浏览器再请求这个资源时,先从缓存中寻找,找到这个资源后,根据它第一次的请求时间和Cache-Control 中设定的有效期,计算出一个资源过期的时间,再拿这个时间跟当前的请求时间比较,如果请求时间在指定时间之前,就会命中强缓存,否则不行;
    4、如果没有命中缓存,浏览器会从服务端重新加载资源并将Cache-Control header记录下来。

    • 区别:Cache-Control是相对时间,在进行缓存命中时都是利用客户端时间进行判断,所以相比较Expires,更为有效和安全。

      这两个header可以用其中一个或者同时使用,同时存在时Cache-Control优于Expires。


三、强缓存的管理:通过如下两种方式设置是否启用强缓存【服务器例如nginx和apache】

 1、通过代码的方式,在web服务器返回的响应中添加Expires和Cache-Control的header;
 2、通过配置web服务器的方式,让web服务器在响应资源的时候统一添加Expires和Cache-Control的header;

 由于在开发时一般不会专门配置强缓存,而浏览器会默认缓存图片、css和js等静态资源,所以开发时经常会因为强缓存而导致资源没有及时更新,解决办法如下:
 1、ctrl+f5;
 2、使用浏览器隐私模式开发;
 3、如果是chrome,可以在network中把缓存禁掉;

禁止缓存

 4、如果缓存问题出现在ajax中,最有效的办法是ajax请求地址追加随机数;
 5、如果使用grunt和gulp等前端工具,通过插件例如grunt-contrib-control来启动一个静态服务器,该服务器下的所有资源返回的response header中,cache-control始终设置为不缓存;

四、强缓存的应用

  • 强缓存是前端性能优化的有力工具,它对于大量的静态资源的网页,很有作用,提高相应速度。通常做法是为这些静态资源全部配置一个超长时间的Expires或者Cache-Control,这样用户访问资源时只需要在第一次的时候加载资源,其他时候只需要在缓存没有失效并且用户没有强制刷新的条件下从缓存中加载。

  • 存在的问题:发布时资源更新问题,更新了资源,但是用户每次请求时依然从缓存中获取原来的资源,除非用户清掉或者强刷新,否则看不到最新的效果。

    • 强缓存还有一点需要注意:通常都是针对静态资源使用,动态资源需要慎用,除了服务端页面可以看作动态资源外,那些引用静态资源的html也可以看作是动态资源,如果这种html也被缓存,当这些html更新之后,可能就没有机制能够通知浏览器这些html有更新,尤其是前后端分离的应用里,页面都是纯html页面,每个访问地址可能都是直接访问html页面,这些页面通常不加强缓存,以保证浏览器访问这些页面时始终请求服务器最新的资源。
  • 强缓存存在问题的解决方案待续~~~


原文博客地址:http://www.cnblogs.com/lyzg/p/5125934.html#rd?sukey=16298ae1a3e33631bf6ebf978f9b1ce8dcaeb2d696193543bb5cb64b79fbc3bca3db85d585c7be90f1fde83d5f15d035

<think>我们将在前端使用浏览器的本地存储(localStorage或sessionStorage)来缓存数据。同时,我们将设计一个缓存策略,包括缓存数据的存储、读取、更新和过期机制。设计思路:1.使用localStorage进行持久化存储,或使用sessionStorage在会话期间存储。2.为每个缓存的数据设置一个过期时间(例如,5分钟)。3.在读取缓存时检查是否过期,如果过期则重新获取数据并更新缓存。4.提供一个缓存管理器类,封装缓存操作。我们将创建一个名为CacheManager的类,包含以下方法:-set(key, data, ttl):存储数据,ttl为缓存有效时间(毫秒)-get(key):获取数据,如果数据不存在或已过期,则返回null-remove(key):移除缓存- clear():清除所有缓存同时,我们还可以考虑使用一个前缀(prefix)来避免与其他应用缓存冲突。代码实现如下:</think># 前端浏览器缓存数据实现方案 在前端开发中,浏览器缓存是提升应用性能和用户体验的关键技术。我将介绍几种常用的浏览器缓存方案,并提供代码实现。 ## 1. localStorage 实现方案 localStorage 提供了一种简单的键值对存储方式,数据在浏览器关闭后仍然保留。 ```javascript // 存储数据 function saveToLocalStorage(key, value) { try { const serializedValue = JSON.stringify(value); localStorage.setItem(key, serializedValue); return true; } catch (error) { console.error('保存到localStorage失败:', error); return false; } } // 读取数据 function getFromLocalStorage(key) { try { const serializedValue = localStorage.getItem(key); return serializedValue ? JSON.parse(serializedValue) : null; } catch (error) { console.error('从localStorage读取失败:', error); return null; } } // 删除数据 function removeFromLocalStorage(key) { localStorage.removeItem(key); } // 使用示例 const userSettings = { theme: 'dark', language: 'zh-CN', fontSize: 16 }; // 存储数据 saveToLocalStorage('user_settings', userSettings); // 读取数据 const savedSettings = getFromLocalStorage('user_settings'); console.log(savedSettings); // {theme: 'dark', language: 'zh-CN', fontSize: 16} // 删除数据 removeFromLocalStorage('user_settings'); ``` ### 优点: - 简单易用 - 存储容量较大(通常5-10MB) - 持久化存储(除非用户清除浏览器数据) ### 缺点: - 同步操作,可能阻塞主线程 - 只能存储字符串 - 同源策略限制 ## 2. sessionStorage 实现方案 sessionStorage 与 localStorage 类似,但数据仅在当前会话中有效。 ```javascript // 存储数据 function saveToSessionStorage(key, value) { try { const serializedValue = JSON.stringify(value); sessionStorage.setItem(key, serializedValue); return true; } catch (error) { console.error('保存到sessionStorage失败:', error); return false; } } // 读取数据 function getFromSessionStorage(key) { try { const serializedValue = sessionStorage.getItem(key); return serializedValue ? JSON.parse(serializedValue) : null; } catch (error) { console.error('从sessionStorage读取失败:', error); return null; } } // 使用示例 const sessionData = { cartItems: [1, 2, 3], lastVisitedPage: '/products' }; saveToSessionStorage('shopping_session', sessionData); ``` ### 适用场景: - 临时会话数据 - 表单草稿保存 - 页面间临时传递数据 ## 3. IndexedDB 实现方案 对于更复杂的数据结构和大数据量,IndexedDB 提供了类似数据库的存储能力。 ```javascript // 打开或创建数据库 function openDB(dbName, version) { return new Promise((resolve, reject) => { const request = indexedDB.open(dbName, version); request.onerror = (event) => { reject(`数据库打开失败: ${event.target.error}`); }; request.onsuccess = (event) => { resolve(event.target.result); }; request.onupgradeneeded = (event) => { const db = event.target.result; // 创建对象存储空间(类似表) if (!db.objectStoreNames.contains('cache')) { const store = db.createObjectStore('cache', { keyPath: 'id' }); // 创建索引 store.createIndex('expires', 'expires', { unique: false }); } }; }); } // 存储数据 async function saveToIndexedDB(data) { const db = await openDB('myCacheDB', 1); return new Promise((resolve, reject) => { const transaction = db.transaction(['cache'], 'readwrite'); const store = transaction.objectStore('cache'); // 添加过期时间 const cacheItem = { ...data, expires: Date.now() + 3600000 // 1小时后过期 }; const request = store.put(cacheItem); request.onsuccess = () => resolve(); request.onerror = (event) => reject(event.target.error); }); } // 读取数据 async function getFromIndexedDB(id) { const db = await openDB('myCacheDB', 1); return new Promise((resolve, reject) => { const transaction = db.transaction(['cache'], 'readonly'); const store = transaction.objectStore('cache'); const request = store.get(id); request.onsuccess = (event) => { const data = event.target.result; // 检查是否过期 if (data && data.expires > Date.now()) { resolve(data); } else { resolve(null); } }; request.onerror = (event) => reject(event.target.error); }); } // 使用示例 const productData = { id: 'product_123', name: '高性能笔记本电脑', price: 1299, description: '最新款高性能笔记本电脑...' }; // 存储 await saveToIndexedDB(productData); // 读取 const cachedProduct = await getFromIndexedDB('product_123'); console.log(cachedProduct); ``` ### 优点: - 支持复杂数据结构 - 异步操作,不阻塞主线程 - 存储容量大(通常50%磁盘空间) - 支持事务和索引 ### 缺点: - API 较复杂 - 需要处理数据库版本迁移 ## 4. 缓存策略实现 结合上述存储方案,实现一个带过期机制的缓存管理器: ```javascript class CacheManager { constructor(storageType = 'localStorage', prefix = 'cache_') { this.storage = storageType === 'localStorage' ? localStorage : sessionStorage; this.prefix = prefix; } // 生成带前缀的键名 getKey(key) { return `${this.prefix}${key}`; } // 设置缓存 set(key, value, ttl = 3600000) { // 默认1小时 const cacheItem = { data: value, expires: Date.now() + ttl }; try { this.storage.setItem(this.getKey(key), JSON.stringify(cacheItem)); return true; } catch (error) { console.error('缓存设置失败:', error); return false; } } // 获取缓存 get(key) { const cached = this.storage.getItem(this.getKey(key)); if (!cached) return null; try { const cacheItem = JSON.parse(cached); // 检查是否过期 if (cacheItem.expires > Date.now()) { return cacheItem.data; } else { // 过期则删除 this.remove(key); return null; } } catch (error) { console.error('缓存解析失败:', error); this.remove(key); return null; } } // 删除缓存 remove(key) { this.storage.removeItem(this.getKey(key)); } // 清除所有带前缀的缓存 clear() { Object.keys(this.storage).forEach(key => { if (key.startsWith(this.prefix)) { this.storage.removeItem(key); } }); } } // 使用示例 const cache = new CacheManager(); // 设置缓存(有效期10秒) cache.set('user_profile', { name: '张三', age: 30 }, 10000); // 立即获取 console.log(cache.get('user_profile')); // {name: '张三', age: 30} // 10秒后获取 setTimeout(() => { console.log(cache.get('user_profile')); // null (已过期) }, 10000); ``` ## 5. Service Worker 缓存策略 对于更高级的缓存需求,可以使用 Service Worker 实现离线缓存: ```javascript // service-worker.js const CACHE_NAME = 'my-app-cache-v1'; const urlsToCache = [ '/', '/index.html', '/styles/main.css', '/scripts/main.js', '/images/logo.png' ]; // 安装阶段:缓存核心资源 self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(urlsToCache)) ); }); // 激活阶段:清理旧缓存 self.addEventListener('activate', event => { event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { if (cacheName !== CACHE_NAME) { return caches.delete(cacheName); } }) ); }) ); }); // 请求拦截:缓存优先策略 self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => { // 返回缓存或网络请求 return response || fetch(event.request); }) ); }); // 注册 Service Worker if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.log('ServiceWorker 注册成功:', registration.scope); }) .catch(error => { console.log('ServiceWorker 注册失败:', error); }); }); } ``` ## 缓存策略选择指南 | 方案 | 适用场景 | 容量限制 | 持久性 | 复杂度 | |------|----------|----------|--------|--------| | localStorage | 用户偏好设置、小量数据 | 5-10MB | 持久 | 低 | | sessionStorage | 会话数据、表单草稿 | 5-10MB | 会话级 | 低 | | IndexedDB | 复杂数据、大数据量 | 50%磁盘 | 持久 | 中高 | | Service Worker | 静态资源、离线应用 | 50%磁盘 | 持久 | 高 | | Cookies | 用户认证、小量数据 | 4KB | 可设置 | 低 | ## 最佳实践 1. **数据分类存储**:根据数据类型选择合适存储方案 2. **设置过期时间**:避免使用过期数据 3. **缓存版本控制**:在键名中包含版本号(如 `cache_v1_user`) 4. **错误处理**:所有缓存操作都应包裹在 try-catch 中 5. **清理机制**:定期清理过期缓存 6. **容量检查**:存储前检查可用空间 ```javascript // 检查 localStorage 可用空间 function checkLocalStorageSpace() { try { const testKey = 'storage_test'; let data = ''; // 填充数据直到达到限制 while (true) { data += '0'.repeat(1024 * 1024); // 每次增加1MB localStorage.setItem(testKey, data); } } catch (error) { localStorage.removeItem(testKey); const usedSpace = Math.round(JSON.stringify(localStorage).length / 1024); console.log(`已使用空间: ${usedSpace}KB`); } } // 使用前检查 if (checkLocalStorageSpace() > 4500) { // 当使用超过4.5MB时 clearExpiredCache(); } ``` ## 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值