笔记三:HTTP的场景实践:Edge缓存策略

120 阅读3分钟

在大项目的初期,我需要在不使用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之后自然而然解决了。