单页应用(SPA)的出现使得前端开发变得更加高效和顺畅。而在 SPA 开发中,合理地处理数据缓存成为了提高应用性能和用户体验的关键。本文将介绍 SPA 应用中常用的数据缓存方案,以及各自的优缺点,帮助读者选择合适的缓存方案。
无缓存方案
在 SPA 应用中,无缓存方案将从 API 服务器获取所需数据,并在用完后立即释放。这是最简单的方式,也是 SPA 最早期的实现方式。对于数据量较小的应用场景,这种方式可以胜任。
// service.js
export const getData = async (id) => {
const response = await fetch(`/api/data/${id}`);
return await response.json();
}
// usage.js
const data = await getData(123); // 获取数据后立即使用缺点是明显的,每次都需要从服务器获取数据,每次获取时也需要等待和处理。因此,这种方式应用于数据量较小且不会频繁变更的场景。对于数据量较大或者经常变更的场景,这种方案很有可能导致用户体验下降。
数据本地缓存方案
数据本地缓存方案将获取到的数据存储在本地,以后再次需要时从本地取出,而不是从服务器获取。
// www.javascriptcn.com code example
// service.js
const CACHE_MAP = {};
export const getData = async (id) => {
if (CACHE_MAP[id]) { // 数据存在,从缓存中获取
return CACHE_MAP[id];
}
const response = await fetch(`/api/data/${id}`);
const data = await response.json();
CACHE_MAP[id] = data; // 将数据保存到缓存
return data;
}
// usage.js
const data1 = await getData(123); // 第一次获取数据
const data2 = await getData(123); // 第二次获取数据,从缓存中获取这种方式能显著提高应用性能和用户体验,尤其是对于经常需要获取数据的单页应用而言,它非常有意义。但同时也存在一些潜在问题,如何防止缓存中的数据过期?如何清理缓存等等。因此,这种方式需要开发者自行思考如何控制缓存。
localStorage 方案
localStorage 是 HTML5 提供的一种新的机制,它能够将数据存储在客户端的浏览器中,并且具有持久性。在实际应用中,可以将数据存储到 localStorage 中,读取时先从 localStorage 中获取,如不存在则从服务器获取,并在取回数据后将数据保存到 localStorage 中,下次就能从 localStorage 中获取。
// www.javascriptcn.com code example
// service.js
const CACHE_KEY_PREFIX = 'DATA_';
export const getData = async (id) => {
const cacheKey = CACHE_KEY_PREFIX + id;
const cacheData = localStorage.getItem(cacheKey); // 查询localStorage
if (cacheData) { // 数据存在,从localStorage获取
return cacheData;
}
const response = await fetch(`/api/data/${id}`);
const data = await response.json();
localStorage.setItem(cacheKey, data); // 将数据保存到localStorage
return data;
}
// usage.js
const data1 = await getData(123); // 第一次获取数据
const data2 = await getData(123); // 第二次获取数据,从localStorage中获取localStorage 方案能够长期存储数据且不受关闭浏览器等行为的影响,下次打开页面或刷新时依然可以读取,因此它比本地缓存方案更加强大。不过,它也存在局限性,如数据占用的内存大小不能超过浏览器和操作系统设定的值。
IndexedDB 方案
IndexedDB 也是 HTML5 提供的一种新的机制,它比 localStorage 更具高级性能,存储大小上限更大,可在客户端浏览器中创建数据库,并以对象存储方式存储所有数据。IndexedDB 方案存储的数据不仅能够在客户端浏览器中长期存储,也能够支持大型数据而不会影响应用性能。
// www.javascriptcn.com code example
// service.js
let database = null;
const getDatabase = () => {
return new Promise((resolve, reject) => {
const openReq = indexedDB.open('DB_DATA', 1);
openReq.onupgradeneeded = () => {
const db = openReq.result;
const store = db.createObjectStore('DATA', { keyPath: 'id' });
store.transaction.oncomplete = () => {
resolve(db);
};
};
openReq.onerror = () => {
reject(openReq.error);
};
openReq.onsuccess = () => {
resolve(openReq.result);
};
});
};
const getFromDb = async (id) => {
if (!database) {
database = await getDatabase();
}
return new Promise((resolve, reject) => {
const store = database.transaction('DATA', 'readwrite').objectStore('DATA');
const fetchReq = store.get(id);
fetchReq.onsuccess = () => resolve(fetchReq.result);
fetchReq.onerror = () => reject(fetchReq.error);
});
}
export const getData = async (id) => {
const cacheData = await getFromDb(id);
if (cacheData) { // 数据存在,从IndexedDB获取
return cacheData;
}
const response = await fetch(`/api/data/${id}`);
const data = await response.json();
await saveToDb(data); // 将数据保存到IndexedDB
return data;
}
const saveToDb = async (data) => {
if (!database) {
database = await getDatabase();
}
return new Promise((resolve, reject) => {
const store = database.transaction('DATA', 'readwrite').objectStore('DATA');
const fetchReq = store.put(data);
fetchReq.onsuccess = () => resolve();
fetchReq.onerror = () => reject(fetchReq.error);
});
}
// usage.js
const data1 = await getData(123); // 第一次获取数据
const data2 = await getData(123); // 第二次获取数据,从IndexedDB中获取IndexedDB 方案是 HTML5 提供的一种开放性高、存储容量大的本地存储方案。但由于它比 localStorage 更加高级,使用难度也更大,因此不建议初学者使用。
如何选择数据缓存方案?
选择数据缓存方案应综合考虑以下几点:
- 数据的大小和频繁程度;
- 数据的重要性、更新频率及时性;
- 已有项目的需求和技术实现栈。
以上,是 SPA 应用中数据缓存方案的选择,希望对你选择合适的缓存方案有所帮助。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67cfa77fe46428fe9eb665c2