Atlaslog / Field Notes / Loading & display
Field note · Loading & display
20 MB GeoJSON parsed synchronously freezes the main thread for 8 s
Quick answer
fetch takes only 600 ms, but L.geoJSON creates 120,000 path objects, computes bounds and binds events, locking the page for about 8 s. JSON.parse is not the bottleneck; per-feature vector object creation is.
Symptom
- A 20.4 MB file with 120,000 polygons locks the page for about 8 s after L.geoJSON(data).addTo(map).
- Performance shows [Violation] 'click' handler took 8120ms with one long task dominating the main thread.
- After load, dragging drops from 60 fps to 12 fps.
Checklist
- Record the load in the Performance panel and see whether the long task sits in parsing or rendering.
- Timestamp after fetch and before L.geoJSON to separate network from parse cost.
- Count features and total vertices; above 500k vertices requires simplification first.
- Reduce to 5,000 features and retest; if the freeze disappears it is a volume problem.
- Check the renderer: the Leaflet SVG renderer degrades past about 10,000 paths.
Fix
Simplify geometry with mapshaper -simplify, clip to the current viewport, or switch to a Canvas renderer or vector tiles; when all data must stay, add features in batches inside requestIdleCallback.
Code
const t0 = performance.now();
const res = await fetch('/data/districts.geojson');
const text = await res.text();
const t1 = performance.now(); // 网络 + 下载
const fc = JSON.parse(text);
const t2 = performance.now(); // 解析
L.geoJSON(fc).addTo(map);
const t3 = performance.now(); // 建对象
console.log('fetch', t1 - t0, 'parse', t2 - t1, 'render', t3 - t2);// npx mapshaper districts.geojson -simplify 10% keep-shapes -o precision=0.0001 out.geojson
const b = map.getBounds();
fetch(`/api/districts?bbox=${b.getWest()},${b.getSouth()},${b.getEast()},${b.getNorth()}`);
L.geoJSON(fc, { renderer: L.canvas({ padding: 0.5 }) }).addTo(map);
// Mapbox GL JS + vector tiles 可承载 10 万级要素
Watch out
- Moving the parse into a Web Worker but still creating 120,000 Leaflet layers on the main thread.
- Lowering numeric precision with a JSON.parse reviver only; that shrinks bytes, not the number of rendered paths.
English edition written for Atlaslog from the original Chinese field note. Code is unchanged and runs as-is.
Atlaslog (2026). 20 MB GeoJSON parsed synchronously freezes the main thread for 8 s. https://www.jingweizhi.com/en/cookbook/geojson-large-freeze.html (accessed 2026-11-03).