百度地图中,咱们会遇到循环建立marker点时内存占用不停上涨致使页面直接崩掉。或者数据量过大页面渲染CPU占用太高致使页面卡死。 如图:前端
使用百度地图展现车辆的位置,而且30s刷新一次位置信息。 面对这样的须要,展现车辆的位置,每个车辆须要一个Marker点,车辆太对须要考虑聚合, 代码实现以下:vue
const clustererInstance = null; const mapInstance = null; // 初始化地图 ... // 建立Marker点 function addMarker(data) { // 建立以前先清除地图上的覆盖物 mapInstance.clearOverlays(); const markers = []; for (let i = 0, len = data.length; i < len; i++) { const item = data[i]; const point = new BMap.Point(item.long, item.lat); const marker = new BMap.Marker(point); markers.push(marker); } if (clustererInstance) { clustererInstance.clearMarkers(); clustererInstance.addMarkers(totalMarkers); } else { clustererInstance = new BMapLib.MarkerClusterer( mapInstance, { markers: markers }); } } 复制代码
这里只是实现建立marker点,定时器和数据请求就不展现了。在每次循环请求数据回来都调用一次addMarker方法,能够完成车辆点的展现。vuex
问题一:数据量小时,这样的实现不会出现明显的问题,可是当数据量达到几万次,或者更大时,页面在循环建立Marker点时,虽然每次都使用clearOverlays,和clearMarkers进行了清除,可是百度的这两个方法并无实现内存释放。致使每次循环浏览器的内存都在不断增长,直到页面崩掉。浏览器
当面对这个问题时,咱们在第一次循环建立marker点时借助vue的store将其存储起来,下一次循环时只是修改marker的postion便可。代码以下:bash
import { mapState } from 'vuex'; const clustererInstance = null; const mapInstance = null; computed: { ...mapState(['allMcMarkers']) }, methods: { // 初始化地图 initMap() { ... }, // 建立Marker点 addMarker(data) { // 建立以前先清除地图上的覆盖物 mapInstance.clearOverlays(); const markers = []; for (let i = 0, len = data.length; i < len; i++) { const item = data[i]; const marker = null; const point = new BMap.Point(item.long, item.lat); // 判断是否存在marker点,有则直接替换位置 if (this.allMcMarkers[i]) { marker = this.allMcMarkers[i]; marker.setPosition(point); } else { marker = new BMap.Marker(point); this.allMcMarkers.push(marker); } markers.push(marker); } if (clustererInstance) { clustererInstance.clearMarkers(); clustererInstance.addMarkers(totalMarkers); } else { clustererInstance = new BMapLib.MarkerClusterer( mapInstance, { markers: markers }); } } } 复制代码
问题二: 当数据量过大时,前端页面渲染内存占用会很大。也会致使页面卡死。因此咱们能够考虑分批渲染。分批渲染可使用setInterval或setTimeout、requestAnimationFrame来实现。markdown
import { mapState } from 'vuex'; const clustererInstance = null; const mapInstance = null; computed: { ...mapState(['allMcMarkers']) }, methods: { // 数据分组 每组5000条数据 group (data) { var result = []; const _l = Math.ceil(data.length / 5000); for (var i = 0; i < _l; i++) { result.push(data.slice(i * 5000, (i + 1) * 5000)); } return result; }, batchRender (data) { return new Promise((resolve, reject) => { var groups = this.group(data); let totalMarkers = []; const that = this; this.renderMarkersLoading = true; const zoom = 5; for (let i = 0; i < groups.length; i++) { // 闭包, 保持i值的正确性 // eslint-disable-next-line wrap-iife window.setTimeout(function () { var group = groups[i]; var index = i; return function () { // 分批渲染 totalMarkers = totalMarkers.concat(that.addMarker(group, zoom, index)); if (totalMarkers.length === data.length) { that.createMarker(totalMarkers); that.renderMarkersLoading = false; } }; }(), 1); } resolve(); }); }, // 建立Marker点 addMarker(data) { // 建立以前先清除地图上的覆盖物 mapInstance.clearOverlays(); const markers = []; for (let i = 0, len = data.length; i < len; i++) { const item = data[i]; const marker = null; const point = new BMap.Point(item.long, item.lat); // 判断是否存在marker点,有则直接替换位置 if (this.allMcMarkers[i]) { marker = this.allMcMarkers[i]; marker.setPosition(point); } else { marker = new BMap.Marker(point); this.allMcMarkers.push(marker); } markers.push(marker); } return markers; }, createMarker (totalMarkers) { if (totalMarkers.length) { if (clustererInstance) { clustererInstance.clearMarkers(); clustererInstance.addMarkers(totalMarkers); } else { clustererInstance = new BMapLib.MarkerClusterer(this.map, { markers: totalMarkers }); } } }, } 复制代码
一样在实现动画的渲染时咱们最优选择requestAnimationFrame实现分批渲染。 上述解决办法可能不是最优的,若是你有更好的解决办法,欢迎留言。闭包