在大项目的初期,我需要在不使用RESTful API的情况下实现auto-suggestion搜索功能,因此考虑使用npm pakage如all-the-package-name将所有的npm包名导入并存储于数组中,不过由于npm包总数超过100万条,每次调用所需时间都会超过5秒,这也导致了每次重新进入搜索页面都会有较长的加载时间,这会对用户的使用体验造成不利影响,因此,我开始考虑使用edge浏览器提供的缓存策略解决此问题。
Edge与其他浏览器类似,常用的缓存方式为四种:cookie, Web storage API (session storage, local storage) 与 indexed DB。
Cookie:
Cookie会将存储的数据发送给服务器,一般用于:
会话状态管理如用户登录状态、购物车、游戏分数或其他需要记录的信息
个性化设置如用户自定义设置、主题和其他设置
浏览器行为跟踪如跟踪分析用户行为等
似乎与本次需求不符,而且考虑到cookie提供的存储空间非常小,不能承载大量的字符串信息,因此并未使用到。
Web storage API:
Web Storage API数据永远不会被传输到服务器,有如下两种:
sessionStorage 为每一个给定的源(origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。
localStorage 与如上所提到的相似,但其存储内容即使浏览器关闭并重新打开也仍然存在,显然更适合当前的情况,每次导入名称时,都会通过检查是否已有cache,如果没有通过setItem添加,如果需要更新则removeItem重新设置。
const loadCachedData = () => {
const cachedData = localStorage.getItem(CACHE_KEY);
const expiryTimestamp = localStorage.getItem(CACHE_EXPIRY_KEY);
if (cachedData && expiryTimestamp) {
if (Date.now() < parseInt(expiryTimestamp)) {
return JSON.parse(cachedData);
} else {
localStorage.removeItem(CACHE_KEY);
localStorage.removeItem(CACHE_EXPIRY_KEY);
}
}
return [];
};
const saveToCache = () => {
const expiryTimestamp...;
const names = require("all-the-package-names");
localStorage.setItem(CACHE_KEY, JSON.stringify(names));
localStorage.setItem(CACHE_EXPIRY_KEY, expiryTimestamp);
};
虽然此方法较为简单,但由于名称数量过多,也超过了localstorage的上限(10MB),因此只剩下一种选择:indexed DB
Indexed DB:
indexed DB使用较为复杂,代码结构如下所示,涉及到了大量async与useEffect的使用
const openDatabase = () => {
return new Promise((resolve, reject) => {
const request = window.indexedDB.open("packageNameCacheDB", 1);
request.onerror = (event) => {
reject("Error.");
};
request.onsuccess = (event) => {
resolve(event.target.result);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore("packageNames", { keyPath: "id" });
store.createIndex("expiryTimestamp", "expiryTimestamp");
};
});
};
const loadCachedData = async () => {
...
};
const saveToCache = async (data) => {
...
};
useEffect(() => {
saveToCache(suggestions);
}, [suggestions]);
};
不幸的是这最后的方法也被证明不可行,由于绑定了useEffect,每次suggestion发生变化,都需要大量时间重新设置cache值,加载包名所需时间变得更长,相对来说更无法接受了。
在权衡之后,all-the-package-names这个包似乎内置了一些处理cache的方法,其实只有初次加载需要较长时间,后续如果不离开页面,刷新非常迅速,考虑到此特性,在改为使用API之前就不再实现缓存了。当然,加载时间过长的问题在使用RESTful API之后自然而然解决了。