解決百度地圖內存泄露問題

百度地圖內存泄露問題

百度地圖中,咱們會遇到循環建立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

setTimeout實現分批渲染

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實現分批渲染。 上述解決辦法可能不是最優的,若是你有更好的解決辦法,歡迎留言。閉包

相關文章
相關標籤/搜索