Уменьшите потребление памяти в Firefox благодаря множеству больших JSON файлов, поступающих через XHR - PullRequest
1 голос
/ 16 марта 2020

Я показываю карту Соединенных Штатов с использованием Leaflet. js, где, если пользователь нажимает на штат, карта увеличивается для просмотра всех переписных участков штата.

Код загружает данные переписи GeoJSON (161,3 МБ), используя 51 запрос XMLHttp в WebWorker, а также состояния Geo JSON (523 КБ), используя 1 запрос XMLHttp в основном потоке.

Существует значительная задержка при первой загрузке страницы, что (EDIT) мне подходит, потому что это неизбежно, учитывая подход, который я использую, и зависит от соединения пользователя inte rnet. Однако только в Firefox (а не в Chrome или Safari) возникают проблемы с памятью. Каждый раз, когда я обновляю sh страницу, память в браузере накапливается, пока браузер не зависнет. Одна только память вкладки выглядит нормально, потому что когда я go до about:performance (диспетчер задач Firefox) и наблюдаю за перезагрузкой страницы, память кажется одинаковой каждый раз. Но в мониторе активности Ma c я вижу увеличение памяти с каждой перезагрузкой.

Я пытался явно удалить переменные в своем коде, но не могу понять, что здесь происходит. Можем ли мы исправить это с помощью Firefox?

Полный HTML, SSCCE:

<head>
    <style>
        body {
            padding: 0;
            margin: 0;
        }

        #map {
            height: 100vh;
            width: 100vw;
        }
    </style>

    <!-- Leaflet -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>

    <!-- my code -->
    <script src="test_script.js"></script>
</head>
<body>
    <div id="map"></div>
</body>

Полный JS, SSCCE:

window.onload = function() {

    /*------------------------------------------------
    -------------- Initialize variables --------------
    ------------------------------------------------*/

    var mapboxAccessToken = 'pk.eyJ1IjoiYnJpZW5uYWtoIiwiYSI6ImNqbXRsNjN0aTAxZXAzbG13bmh0dGFjNm0ifQ.98TAXgq4Rg1LpM2Oq1rlWw';


    function reqListener() {
        statesData = JSON.parse(this.response);
    }

    // Get main data
    var xhr = new XMLHttpRequest();
    var url = 'http://briennakh.me/accessibility-maps/data/us_states_edited.json?v=' + new Date().getTime()
    xhr.addEventListener('load', reqListener);
    xhr.open('GET', url, false);
    xhr.send();

    /*------------------------------------------------
    -------------- Create map ------------------------
    ------------------------------------------------*/

    // Create basemap 
    var basemap = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
        id: 'mapbox/light-v9',
        attribution: '',
        tileSize: 512,
        zoomOffset: -1,
        maxZoom: 18,
        accessToken: mapboxAccessToken,
    });

    // Create map 
    var map = L.map('map', {
        center: new L.LatLng(37.8, -96),
        zoom: 4,
        layers: [basemap],
    });

    var stateLayer = L.geoJson(statesData, {
        style: stateStyle,
        onEachFeature: onEachState
    }).addTo(map);

    var censusTractLayers = {};

        if (typeof(Worker) !== "undefined") {
        w = new Worker('worker.js'); // to test worker, must serve on localhost, otherwise Security Error

        // Respond to message sent back from worker
        w.onmessage = function(e) {
            var state = e.data;
            console.log('Received message from worker for ' + state.name)
            censusTractLayers[state.name] = L.geoJson(state, {
                style: tractStyle,
                onEachFeature: onEachTract
            });
        }
    } else {
        // will need to inform user they need an updated browser
        console.log('No support for web worker.');
    } 

    // Load each state's census tracts in the background
    w.postMessage(statesData.features);

    /*------------------------------------------------
    -------------- Define styles ---------------------
    ------------------------------------------------*/
    function tractStyle(feature) {
        return {
            fillColor: 'grey',
            weight: .5, // no border
            opacity: 1,
            color: 'white',
            dashArray: '1',
            fillOpacity: 0.7
        }
    }

    function stateStyle(feature) {
        return {
            fillColor: 'grey',
            weight: 2,
            opacity: 1,
            color: 'white',
            dashArray: '3',
            fillOpacity: 0.7
        };
    }

    /*------------------------------------------------
    -------------- Define event handlers -------------
    ------------------------------------------------*/
    function onEachState(feature, layer) {
        layer.on({
            mouseover: function(e) {
                highlightFeature(e);
            },
            mouseout: function(e) {
                var feature = e.target;
                stateLayer.resetStyle(feature);
            },
            click: function(e) {
                map.fitBounds(e.target.getBounds());

                // Add census tract layer to map if it has already been loaded
                if (feature.properties.name in censusTractLayers) {
                    censusTractLayers[feature.properties.name].addTo(map);
                } else {
                    console.log('Not loaded yet');  
                }
            }
        });
    }

    function onEachTract(feature, layer) {
        layer.on({
            mouseover: function(e) {
                highlightFeature(e);
            },
            mouseout: function(e) {
                var feature = e.target;

                for (i in censusTractLayers) {
                    if(censusTractLayers[i].hasLayer(feature)) {
                        censusTractLayers[i].resetStyle(feature);
                    }
                }
            }
        });
    }

    function highlightFeature(e) {
        var feature = e.target;

        feature.setStyle({
            weight: 5,
            color: '#666',
            dashArray: '',
            fillOpacity: 0.7
        });

        if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
            feature.bringToFront(); // to prevent feature overlaps  
        }
    }
}

JS для веб-работника:

function reqListener() {
    postMessage(this.response);
}

onmessage = function(e) {
    console.log('Message received from main script.');

    for (var i in e.data) {
        state = e.data[i].properties.name;
        var xhr = new XMLHttpRequest();
        var url = 'http://briennakh.me/accessibility-maps/data/census tracts/geojsons/' + state + '.json?v=' + new Date().getTime();
        xhr.addEventListener('load', reqListener);
        xhr.open('GET', url);
        xhr.responseType = 'json';
        xhr.send();
    }
}
...