问题初现
公司项目需要在地图上展示超过一万个覆盖物,数量最多可达到两万以上。一开始,我们发现聚合点的生成速度尚可,大约需要500毫秒。然而,当聚合点生成完毕后,用户在操作地图,比如进行缩放或移动时,会发现地图运行变得非常缓慢。在日常生活中,当用户快速缩放地图以查看更广区域时,页面常常会停滞不动,这极大地影响了使用感受。
新问题暴露
在后续的改进过程中,我们又发现了两个问题。首先,如果在聚合点加载之前用户对地图进行了操作,那么加载过程会变得极其缓慢,甚至超过1000毫秒。其次,每次删除聚合点后再重新添加,速度都会逐渐减慢。举个例子,最初加载聚合点只需要100毫秒,但随着操作次数的增加,加载速度明显变慢。这些问题严重影响了项目在实际使用中的效果。
卡顿多情况
地图上除了聚合点问题,还存在其他可能导致操作不畅的情况。首先,地图覆盖物过多时,操作起来会变得缓慢。这是因为百度地图需要实时计算这些覆盖物的位置,而覆盖物数量过多,计算量巨大,从而影响了界面的流畅度。其次,在同时添加众多覆盖物时,也会出现卡顿现象。在处理复杂地图场景时,这两种卡顿现象尤为常见。
方案一思路
/**
* @param point {BMap.Point}
*/
function isVisible(point){
const bounds = bMapInstance.getBounds()
return bounds.containsPoint(point)
}
为解决地图操作卡顿,我们实施了一种监听百度地图相关事件的策略。当发生moving或zoomstart事件时,地图上的所有覆盖物会被移除;而在moveend或zoomend事件触发后,用户能看到的地图部分将被重新加载。线上测试表明,使用movestart时出现问题,用户点击地图激活movestart后,并未触发moveend,功能表现异常。这可能是由于浏览器版本较旧,存在兼容性问题。
/**
* @param bounds {BMap.Bounds}
* @return {boolean}
*/
function isVisible(bounds) {
const bMapBounds = bMapInstance.getBounds()
return !!bMapBounds.intersects(bounds)
}
方案二要点
操作地图时,推荐使用moving事件。movestart事件在用户点击地图时激活,但后续不会触发moveend事件,这会导致功能无法正常工作。此外,还需实施防抖措施,因为moveend和zoomend事件的发生并不代表操作已结束,短时间内还有可能再次触发moving和zoomstart事件。所以必须要有防抖操作,避免功能异常。
分批次添加
处理因覆盖物过多导致的运行不畅,我们采取分阶段向地图中添加覆盖物。确保每阶段添加不会造成明显延迟,并在每阶段之间设置定时器,以便页面有足够时间处理用户操作和渲染。虽然这样做会延长操作时间,但能显著改善卡顿问题。这种方法在大型地图项目中使用,大大提升了用户的操作感受。
export function addStartAndEndEventToBMap(bMapInstance, start, end) {
let doing = false
function _start() {
if (doing) return
doing = true
start()
}
function _end() {
if (!doing) return
doing = false
setTimeout(() => !doing && end(), 200)
}
bMapInstance.addEventListener("zoomstart", () => {
_start()
})
bMapInstance.addEventListener("moving", () => {
_start()
})
bMapInstance.addEventListener("moveend", () => {
_end()
})
bMapInstance.addEventListener("zoomend", () => {
_end()
})
}
这是对地图项目覆盖层出现卡顿现象及其解决方法的详尽阐述。遇到这些棘手的卡顿,我们持续寻求有效的解决途径。在使用地图软件时,你是否也遭遇过类似的卡顿?不妨点赞并转发这篇文章,同时在评论区留下你的看法。