百度地圖中,咱們會遇到循環建立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實現分批渲染。 上述解決辦法可能不是最優的,若是你有更好的解決辦法,歡迎留言。閉包