从OpenLayers 8.2.0升级到10.2.1致自定义缓存瓦片加载函数失效
OpenLayers 8.2.0 升级到 10.2.1 后矢量瓦片预加载失效导致闪烁问题的解决方案
问题根源分析
从OpenLayers 8.x到10.x的版本迭代中,VectorTile的加载机制发生了核心变更:
- OL9+开始限制
tile.setLoader()的自定义使用场景,VectorTileSource内部会接管瓦片的加载流程,直接在tileLoadFunction中设置loader会被内部逻辑覆盖,导致自定义的缓存判断和预加载逻辑无法正确触发。 - 异步加载的处理逻辑更严格,原代码中依赖loader的异步回调执行预加载,可能因OL内部的状态管理被忽略。
修复方案
重构自定义tileLoadFunction,跳过tile.setLoader(),直接在tileLoadFunction内完成缓存校验、加载逻辑和预触发:
修改后的代码
import { VectorTileSource, VectorTile } from 'ol/source'; import { MVT } from 'ol/format'; import { Extent, ProjectionLike } from 'ol/proj'; import { Feature, Geometry } from 'ol'; import axios from 'axios'; import { useVectorTileStore } from './your-store-path'; // 替换为实际路径 export class VectorTileSourceWithCache extends VectorTileSource { constructor(options: any) { // 可根据OL10的Options类型调整 super(options); this.tileLoadFunction = this.tileLoadFunctionWithCache.bind(this); } private async preloadAllInstances(baseUrl: string, tile: VectorTile, extent: Extent, projection: ProjectionLike): Promise<void> { const vectorTileStore = useVectorTileStore(); const instants = [/* 你的时刻数组 */]; const urls: string[] = []; for (const instant of instants) { // 构建对应时刻的瓦片URL const url = this.buildInstantUrl(baseUrl, instant); // 替换为实际URL构建逻辑 urls.push(url); } vectorTileStore.addUlrsToPreloadQueue(urls, tile, extent, projection); } // 新增URL构建辅助方法(可选,优化代码结构) private buildInstantUrl(baseUrl: string, instant: any): string { // 示例:替换URL中的时刻参数 return baseUrl.replace('{instant}', instant.toString()); } private tileLoadFunctionWithCache(tile: VectorTile, url: string): void { const vectorTileStore = useVectorTileStore(); const format = tile.getFormat() as MVT; const tileExtent = tile.getExtent(); const tileProjection = tile.getProjection(); // 1. 检查瓦片是否在产品边界内 if (!vectorTileStore.isTileInProductBounds(url)) { tile.setFeatures([] as Array<Feature<Geometry>>); this.preloadAllInstances(url, tile, tileExtent, tileProjection).catch(console.error); return; } // 2. 检查缓存是否存在 if (vectorTileStore.isTileLoaded(url)) { const data = vectorTileStore.getDataByUrl(url); if (data) { const features = format.readFeatures(data, { extent: tileExtent, featureProjection: tileProjection }); tile.setFeatures(features as Array<Feature<Geometry>>); } else { tile.setFeatures([] as Array<Feature<Geometry>>); } this.preloadAllInstances(url, tile, tileExtent, tileProjection).catch(console.error); return; } // 3. 缓存不存在时发起请求 console.log("PBF not found, requesting..."); axios.get(url, { responseType: "arraybuffer" }) .then(response => { if (response.status !== 200) { tile.setFeatures([] as Array<Feature<Geometry>>); return; } const data = response.data; const features = format.readFeatures(data, { extent: tileExtent, featureProjection: tileProjection }); tile.setFeatures(features as Array<Feature<Geometry>>); vectorTileStore.addFeatures(url, data, format, tileExtent, tileProjection); // 触发预加载 this.preloadAllInstances(url, tile, tileExtent, tileProjection).catch(console.error); }) .catch(error => { console.error("Error loading tile:", error); tile.setFeatures([] as Array<Feature<Geometry>>); this.preloadAllInstances(url, tile, tileExtent, tileProjection).catch(console.error); }); } }
关键修改点
- 移除
tile.setLoader():直接在tileLoadFunction中处理所有加载逻辑,避免被OL内部逻辑覆盖。 - 使用瓦片自身的extent和projection:替换原loader参数中的
extent和projection,确保与OL10中瓦片的状态一致。 - 预加载逻辑独立触发:在每一个分支(边界判断、缓存命中、加载完成/失败)都触发预加载,确保逻辑不遗漏。
- 异步错误处理:预加载的异步调用添加
catch,避免未处理的Promise异常阻塞流程。
额外检查项
- 确认
vectorTileStore的缓存键(URL)与OL10中瓦片请求的URL完全一致,避免因URL参数顺序、编码差异导致缓存不命中。 - 检查预加载队列的处理逻辑,确保预加载的瓦片数据被正确存入缓存,且后续请求能正确读取。
内容的提问来源于stack exchange,提问作者Joan Morilla
相关产品推荐
相关产品推荐

