从O(n^2)到O(n)最后到O(1),究竟经历了什么?

571 阅读2分钟

最近在开发项目的过程中,使用了高德地图,算是踩的一些坑,做了一些优化

//初始化地图对象,加载地图
      var map = new AMap.Map('container', { resizeEnable: true });
      MAP.current = map;
      for (var i = 0, marker; i < res.length; i++) {
        const latitude = res[i][0] // 用户纬度
        const longitude = res[i][1] // 用户经度
        var marker = new AMap.Marker({
           position: [ longitude, latitude],
           icon: master_position,
           map: map,
        });
        
        marker.content = '88888' 
        marker.on('click', markerClick);
        marker.emit('click', { target: marker });
      }
      
      // 点击图标
      function markerClick(e) {
         //这里遍历将原来的其他图标设置为默认的
         for (let i = 0; i < markers.length; i++) {
           const ele = markers[i];
           ele.setIcon(master_position);
           console.log(i);
         }

       
        e.target.setIcon(master_position_active); //这里是选中的 marker 单独设置样式
        infoWindow.setContent(e.target.content);
        infoWindow.open(map, e.target.getPosition());
     
      }
      map.setFitView();
      
    });

看起来好像没什么毛病 但是 最坑的地方来了

image.png

这个函数绑定的时候会直接触发,而不是等点击的时候触发 这就导致了 markerClick这个函数里面的 for循环也会触发 如果 100条数据,就直接循环了1万次,想想就坑

既然知道了问题所在,那我们就开始来解决问题

既然每次挂载的时候就会触发 markerClick 函数,那么我们是不是可以加个状态,只有等地图都加载完成,再让我们的mackerClcik执行 说干就干

第一步

//再原来的 for循环前面加个状态
let flag = false;
//这里遍历将原来的其他图标设置为默认的
         for (let i = 0; i < markers.length; i++) {
           const ele = markers[i];
           ele.setIcon(master_position);
           console.log(i);
         }

第二步

地图加载完成 再更改 flag 状态

 map.setFitView(); //这里地图完成
flag = true; //地图初始化完成 就是这一步

改完之后进行测试,好家伙,果然可以,瞬间变成 O(N)

虽然上面的已经优化了,但是还有没有优化的空间,于是我们继续改造

通过看代码,很容易发现,我们每次打开一个marker 都要把之前的所有 marker的图标重新设置一次,这无疑是一种浪费,那么我就从这入手,继续优化,

有了 想法,我们就去行动,既然我们想要的只是,打开的 marker的样式不同,那么我们是不是可以只设置当前的marker 就行了,这样就不需要 把之前的所有的 icon 都设置一遍

image.png 重要的就是,设置一个值来存储之前的 marker 状态,

image.png

ok,大功告成! 这是在项目开发中遇到的一些问题,如果大家有更好的想法,欢迎探讨!