useCesiumCache Cesium 资源缓存工具使用文档
useCesiumCache Cesium 资源缓存工具使用文档
概述
useCesiumCache 是一个针对 Cesium.js 的请求缓存工具,通过拦截 Cesium 底层资源加载方法(Cesium.Resource._Implementations.loadWithXhr),将符合条件的请求响应(如 blob 或 arraybuffer)自动缓存到浏览器的 IndexedDB 中。当同一资源再次被请求时,直接从本地缓存返回,大幅减少网络请求、提升 3D 场景的加载速度,并支持一定的离线能力。
功能特性
- 🚀 无缝集成:只需调用一次初始化函数,即可自动拦截所有 Cesium 的
Resource请求,无需修改现有 Cesium 业务代码。 - 💾 IndexedDB 持久化:利用浏览器 IndexedDB 存储二进制数据(Blob/ArrayBuffer),容量大、持久化保存,页面刷新后依然有效。
- 🎯 可配置缓存策略:
- 支持按 URL 或自定义键(
key函数)缓存。 - 可指定缓存的响应类型(如
"blob"、"arraybuffer")。 - 可选择性忽略某些请求(通过返回空字符串的
key函数)。
- 支持按 URL 或自定义键(
- 🧠 智能拦截:仅对匹配
types的responseType进行缓存操作,其他请求(如json、text)按原始流程处理。 - 📊 缓存管理:提供清除所有缓存、获取缓存大小的方法,便于维护。
- 🔍 调试模式:开启
debug: true后控制台会输出缓存命中/未命中/存储的日志,方便开发和调优。
依赖要求
- Cesium.js:项目需已引入 Cesium(版本不限,但建议使用较新版本),并可通过全局
Cesium对象访问,或通过import * as Cesium from 'cesium'引入。 useLocalStore:工具内部依赖sunrise-utils中的useLocalStore模块,该模块封装了 IndexedDB 的基础操作(getCacheByKey、setCacheToLocal、clearCache、getCacheSize)。如果你的项目中没有该模块,请确保有对应的实现或从合适路径导入。
配置参数
调用 useCesiumCache(config, Resource?) 时可传入以下配置对象:
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
dbName | string | "LocalStore" | IndexedDB 数据库名称,将透传给 useLocalStore |
key | (url, responseType, method, data, headers) => string | (url) => url | 生成缓存键的函数,返回的字符串将作为存储的 key。若返回空字符串(""),则不缓存该请求。可用于实现精细化缓存策略(如忽略某些 URL 或带参数的请求) |
types | Array<ResponseType> | ["blob", "arraybuffer"] | 需要缓存的响应类型数组。只有请求的 responseType 在此列表中时,才会尝试缓存。Cesium 中常见的类型有 "blob"(影像瓦片、地形等)和 "arraybuffer"(3D Tiles、模型等) |
debug | boolean | false | 是否在控制台输出缓存操作日志(命中、未命中、已存储) |
参数详解
key函数:接收请求参数,返回唯一标识该资源的键。默认使用url作为键。如果你的瓦片 URL 包含时间戳或会话参数导致同一资源 URL 变化,可通过自定义key函数去除无关参数,实现共享缓存。例如:key: (url) => url.split('?')[0] // 忽略查询参数
若返回"",则请求不会被缓存,直接走网络。types数组:Cesium 内部loadWithXhr可能请求多种类型数据,如"json"(样式文件)、"text"(某些元数据)。通常我们只需缓存体积较大的二进制数据,因此默认只缓存"blob"和"arraybuffer"。可根据需要添加其他类型,但不建议缓存文本类型,以免干扰实时更新。
返回对象方法
调用 useCesiumCache 后返回一个对象,包含以下方法:
clear(): void
清除所有缓存的资源(即清空整个 IndexedDB 数据库)。调用后所有已缓存的瓦片、模型等将被删除,下次请求会重新从网络加载。
getCacheSize(): Promise<string>
获取当前缓存的总大小,返回一个格式化的字符串(如 "1.2 MB")。此方法直接透传 useLocalStore.getCacheSize() 的结果。
注意:返回的对象中还可能包含其他内部属性,但主要使用上述两个方法。
useCesiumCache设计为单例模式,多次调用不会重复拦截,且每次返回相同的缓存管理对象。
使用示例
1. 基础用法(自动拦截所有 Cesium 请求)
import * as Cesium from 'cesium';
import { useCesiumCache } from './useCesiumCache';
// 初始化缓存(只需在应用启动时调用一次)
useCesiumCache({
debug: true, // 开发环境下可开启调试
});
// 之后正常使用 Cesium,所有影像、地形、3D Tiles 等请求都会被自动缓存
const viewer = new Cesium.Viewer('cesiumContainer');
2. 自定义缓存键(忽略 URL 中的版本参数)
useCesiumCache({
key: (url, responseType, method, data, headers) => {
// 例如 https://example.com/tiles/{z}/{x}/{y}?v=123 => https://example.com/tiles/{z}/{x}/{y}
return url.split('?')[0];
},
debug: true,
});
3. 排除某些 URL 不缓存
useCesiumCache({
key: (url) => {
if (url.includes('/dynamic/')) {
return ''; // 返回空字符串表示不缓存动态数据
}
return url;
},
});
4. 管理缓存(清除/查看大小)
const cache = useCesiumCache({ debug: false });
// 获取缓存大小并显示
cache.getCacheSize().then(size => {
console.log(`当前缓存占用: ${size}`);
});
// 用户点击“清除缓存”按钮时
document.getElementById('clear-cache').onclick = () => {
cache.clear();
alert('缓存已清除');
};
5. 与现有 Cesium 代码集成(确保拦截生效)
拦截器在第一次调用 useCesiumCache 时被安装。务必在所有 Cesium 资源请求发生之前调用它。通常放在应用入口文件(如 main.ts 或 index.ts)中,并在创建 Cesium.Viewer 之前执行。
工作原理(简要)
- 工具通过替换
Cesium.Resource._Implementations.loadWithXhr方法实现对 Cesium 底层网络请求的拦截。 - 对于每个请求,根据
config.key生成缓存键,并判断responseType是否在config.types中。 - 若需缓存,先查询 IndexedDB 是否已有对应键的数据。
- 命中:直接使用缓存数据,通过
deferred.resolve返回,避免网络请求。 - 未命中:调用原始
loadWithXhr发起网络请求,并在请求成功后通过包装的resolve将数据存入 IndexedDB。
- 命中:直接使用缓存数据,通过
- 使用
used标志确保拦截逻辑只安装一次,避免重复覆盖。
注意事项
- 单例行为:多次调用
useCesiumCache只有第一次会安装拦截器,后续调用均返回相同的缓存管理对象。因此你可以在多个模块中调用它,但最好只在入口调用一次。 - Cesium 版本兼容性:工具依赖于 Cesium 内部
Resource._Implementations.loadWithXhr的接口。不同 Cesium 版本该结构可能发生变化。目前测试于 Cesium 1.80+,若遇到拦截失效,请检查对应版本的 Cesium 源码,调整代码中的类型定义或属性访问路径。 - 跨域与 CORS:缓存的数据来源于网络请求,因此跨域资源仍需服务端支持 CORS,否则原始请求会失败,缓存也无法生效。
- 缓存更新:默认策略是“一次缓存,永久使用”。若资源在服务端更新(如新版本地形数据),需要手动调用
clear()清除缓存,或通过key函数加入版本标识(例如将版本号拼入 key)。 - 异步初始化:IndexedDB 操作是异步的,但缓存查询在网络请求发起前完成,因此不会阻塞原始请求流程。若缓存查询失败(如 IndexedDB 异常),会自动回退到网络请求。
useLocalStore的导入路径:示例中从"sunrise-utils"导入,请根据你的项目实际情况调整路径。若没有该模块,需要自行实现或替换为其他存储方案(如 idb 库),并确保导出方法签名匹配。
常见问题
Q:为什么我的缓存没有生效?
A:请检查:
- 是否在所有 Cesium 请求之前调用了
useCesiumCache? - 是否开启了
debug: true?控制台应输出[CesiumCache] Miss:或[CesiumCache] Hit:日志。若没有任何日志,可能拦截器未正确安装。 - 请求的
responseType是否在config.types中?Cesium 默认缓存类型为blob和arraybuffer,如果你的请求是json或text,默认不会被缓存。 - 自定义
key函数是否返回了空字符串导致被忽略?
Q:清除缓存后,下次请求会重新下载吗?
A:是的,调用 clear() 会删除所有 IndexedDB 中的缓存数据,之后所有请求都会重新从网络获取并再次缓存。
Q:缓存占用的空间有限制吗?
A:IndexedDB 没有严格的上限,但浏览器通常会根据可用磁盘空间动态分配。长时间使用可能导致缓存过大,建议提供管理界面让用户手动清除,或实现 LRU 淘汰策略(本工具暂未内置)。
Q:离线模式下能使用缓存的瓦片吗?
A:可以,只要之前访问过的区域已被缓存,即使断网也能正常显示。但首次访问的瓦片会因网络失败而无法加载。
Q:如何预缓存某些区域的瓦片?
A:可以手动遍历需要的瓦片坐标,构造 Cesium.Resource 对象发起请求,利用缓存拦截自动存储。例如使用 Cesium.Resource.fetchImage 或 Cesium.Resource.fetchArrayBuffer 来加载影像或地形。
通过 useCesiumCache,你可以轻松为 Cesium 应用添加强大的缓存能力,显著提升用户体验,尤其在重复浏览同一区域或需要离线使用的场景下。如有任何问题,欢迎反馈!