JSON 工具箱

大 JSON 解析很慢怎麼優化

結論:優化順序錯了,換什麼函式庫都沒用。先量出時間花在解析、渲染還是請求上,再按「減少解析次數 → 串流處理 → 移到 Worker → 換二進位格式」逐級加碼。

進階約 5 分鐘發佈於 2026-10-30更新於 2026-10-30
大 JSON 解析的效能優化順序

結論:先量出網路、解析與渲染各佔多少時間,多數「解析慢」其實是渲染慢;優化按「減少解析次數 → 拆小回應體 → 串流解析 → 移到 Worker → 換二進位格式」的順序逐級加碼,換函式庫放在最後。

先別換函式庫。多數「解析慢」在加一次 console.time 之後會發現是渲染慢。

第一步:量清楚時間花在哪

const startFetch = performance.now();
const response = await fetch(url);
const text = await response.text();
const startParse = performance.now();
const data = JSON.parse(text);
const startRender = performance.now();
render(data);

分四段記錄:網路、讀流、JSON.parse、渲染。三段耗時占比不同,優化手段完全不同:

占比最高的是 真正的問題 對策
網路 回應體太大 欄位裁剪、分頁、gzip/brotli
JSON.parse 資料量本身大 減少解析次數、串流、Worker
渲染 一次渲染上萬節點 虛擬列表、分頁渲染、折疊

JSON.parse 是原生實作,速度不慢:現代瀏覽器解析 1MB JSON 大約 5–15ms,10MB 大約 80–150ms。如果測出來 10MB 要 2 秒,問題多半不在 parse。

第二步:減少解析次數

收益最高、最容易被忽略。

  • 別反覆解析同一份資料。 十個元件各自 JSON.parse(localStorage.getItem(...)) 就是解析十次,提到模組層級快取一次。
  • 別用 JSON.parse(JSON.stringify(x)) 做深拷貝。 代價是資料量的兩倍以上,改用 structuredClone。
  • 別在主執行緒解析完再傳給 Worker。 postMessage 會再複製一次。把原始文字傳給 Worker,讓它自己解析。
  • 按需取欄位。 只需要三個欄位時,後端就該裁剪。

第三步:拆小回應體

分頁用 page/size,大資料集用游標而不是 offset,列表介面只回摘要欄位。這一步的效果通常比任何前端優化都大,因為它同時減少了網路、解析與記憶體佔用。

第四步:串流解析

資料必須整體處理、又確實很大時,用串流解析器逐塊處理:

import { parser } from 'stream-json';
import { streamArray } from 'stream-json/streamers/StreamArray';

const pipeline = fs.createReadStream('big.json').pipe(parser()).pipe(streamArray());
for await (const { value } of pipeline) {
  await handleOne(value);
}

代價是程式碼複雜度上升,且不能隨機存取——只適合「逐條處理」。

第五步:移到 Worker

解析本身不慢,但會阻塞主執行緒。把解析放進 Web Worker,注意傳的是原始文字,傳已解析的物件會觸發結構化複製,等於把開銷翻倍。

第六步:換格式(最後考慮)

內部系統之間傳輸、體積穩定在幾十 MB 時,可以考慮 NDJSON(一行一條,天生可串流)或 Protobuf/MessagePack。這屬於「換協定」,需要兩端一起改。

別做的事

  • 用 eval 解析 JSON:安全風險,且不一定更快
  • 為了「優化」把 JSON 轉成字串再塞進 JSON:體積翻倍
  • 在主執行緒迴圈幾十萬次 JSON.parse 小字串:合併成一次解析

常見問題

如何判斷瓶頸在解析還是渲染?

用 performance.now() 把請求、讀流、JSON.parse 與渲染分成四段計時,佔比最高的那一段才是真正的瓶頸。現代瀏覽器解析 1MB JSON 約 5–15ms、10MB 約 80–150ms,如果 10MB 要 2 秒,問題多半不在 parse。

為什麼說換函式庫通常解決不了問題?

JSON.parse 是原生實作,速度不慢,多數「解析慢」來自重複解析或一次渲染上萬節點。換函式庫通常只能帶來 10%–30% 的提升,而減少一次全量解析往往能省一半。

是否應該把解析放進 Web Worker?

當解析阻塞主執行緒、頁面卡住或動畫掉幀時應該放進 Worker。注意要傳原始文字而不是已解析的物件,否則 postMessage 的結構化複製會把開銷翻倍。

延伸閱讀