发现问题
在开发webmap时遇到一个需求,即鼠标在Mapbox GL JS创建的地图中移动时不执行mousemove事件,等鼠标停止后执行。那么很容易想到的代码是下面这样的。
let timeoutfn;
function throttleMousemove(e){
console.log(e.features); // 输出 features
if (timeoutfn) {
clearTimeout(timeoutfn);
}
timeoutfn = setTimeout(function () {
console.log(e.features); // 输出 undefined
}, 50);
}
// 添加mousemove事件
map.on("mousemove", '测试图层', throttleMousemove);
很简单的实现,在setTimeout方法中获取Event对象,然后输入该对象的features属性。
但是,setTimeout中的console.log(e.features)
输出的是 undefined
,没错,确定是undefined
。
解决问题
因为业务代码比较复杂,首先想到的是数据在上下文变更了,然后排查上下文业务代码,各种业务逻辑都注释掉,也没发现问题,最后精简代码,只有上面的简单的监听事件,问题还是存在。
难道,Mapbox GL JS可能需要时间来解析鼠标所在位置下的地图特性(features),这些特性可能不是立即可用的?这也不可能啊,明显可以知道setTimeout内部的执行时间比外部要靠后,外部可以获取,内部不可能获取不到。
难道因为数据量大被垃圾回收机制自动给回收了?这个更不可能了,setTimeout 内部可以获取到e
对象的,没道理只回收features属性。这个时候考虑是不是e.features被Mapbox GL JS库的开发者销毁了?
难道这是Mapbox GL JS内部机制的问题?Mapbox GL JS可能在事件处理的某些阶段对事件对象进行了修改或清理操作,特别是在处理大量数据交互时,为了性能考虑,可能释放了非必需的资源?这确实也可能导致某些属性在异步回调中不可用。
然后我去扒了Mapbox GL JS的源码,确认了我的想法,确实是Mapbox GL JS内部机制的问题,在事件执行完之后,确实将e.features给回收了。贴一下部分源码:
_createDelegatedListener(type: keyof MapEventType | string, layerId: string, listener: Listener): {
layer: string;
listener: Listener;
delegates: