سریعتر کردن تجزیه JSON بزرگ
جمعبندی: بهینهسازی با ترتیب اشتباه هر تعویض کتابخانهای را بیفایده میکند. شبکه، تجزیه و رندر را جدا اندازه بگیرید، سپس تجزیهها را کم کنید، payload را کوچک کنید و جریان دهید.

جمعبندی: اول شبکه، تجزیه و رندر را جدا اندازه بگیرید — بیشتر «تجزیه کند» در واقع رندر کند است — سپس نردبان را به ترتیب بالا بروید: تجزیه کمتر، payload کوچکتر، جریان، worker، و قالب دودویی در آخر.
با تعویض کتابخانه شروع نکنید. یک زمانسنج اضافه کنید و معمولاً میبینید رندر مشکل است.
گام اول: مراحل را اندازه بگیرید
const t0 = performance.now();
const response = await fetch(url);
const text = await response.text();
const t1 = performance.now();
const data = JSON.parse(text);
const t2 = performance.now();
render(data);
const t3 = performance.now();
| مرحله غالب | مشکل واقعی | اصلاح |
|---|---|---|
| شبکه | payload بیش از حد بزرگ | انتخاب فیلد، صفحهبندی، فشردهسازی |
JSON.parse |
ورودی واقعاً بزرگ | تجزیه کمتر، جریان، worker |
| رندر | دهها هزار گره یکجا | لیست مجازی، صفحهبندی، جمعکردن |
مرورگرهای مدرن ۱ مگابایت را تقریباً در ۵ تا ۱۵ میلیثانیه و ۱۰ مگابایت را در ۸۰ تا ۱۵۰ میلیثانیه تجزیه میکنند. اگر ۱۰ مگابایت دو ثانیه طول میکشد، JSON.parse گلوگاه شما نیست.
گام دوم: کمتر تجزیه کنید
ارزانترین برد، و نادیدهگرفتهشدهترین.
- تجزیه مکرر همان payload را متوقف کنید. ده کامپوننت که هر یک
JSON.parse(localStorage.getItem(...))صدا میزنند یعنی ده تجزیه. یک بار در سطح ماژول کش کنید. - استفاده از
JSON.parse(JSON.stringify(x))برای شبیهسازی عمیق را متوقف کنید. بیش از دو برابر حجم داده هزینه دارد؛structuredCloneندارد. - روی رشته اصلی تجزیه نکنید و بعد شیء را به worker نفرستید.
postMessageدوباره کلونش میکند. متن خام بفرستید و بگذارید worker تجزیه کند. - فیلد کمتر بخواهید. اگر رابط کاربری سه ویژگی میخواهد، API نباید سیصد بفرستد.
گام سوم: payload را کوچک کنید
صفحهبندی با page/size، cursor بهجای offset عمیق، فیلدهای خلاصه در endpointهای فهرست. این معمولاً از مجموع همه بهینهسازیهای فرانتاند بهتر است، چون شبکه، تجزیه و حافظه را همزمان کم میکند.
گام چهارم: جریان دهید
وقتی داده باید بهعنوان یک کل پردازش شود و واقعاً بزرگ است:
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 بگذارید و متن را بفرستید، نه شیء تجزیهشده، وگرنه کلون ساختاری هزینه را دو برابر میکند.
گام ششم: قالب را عوض کنید، در آخر
برای ترافیک داخلی که بهطور مداوم دهها مگابایت است، NDJSON طبیعی جریان میشود و Protobuf یا MessagePack کوچکتر و سریعترند. هر دو تغییر پروتکلاند و هماهنگی میخواهند.
نکنید
evalکردن JSON: ناامن و سریعتر نیست- stringify کردن JSON برای جاسازی در JSON: اندازه را دو برابر میکند
- تجزیه صدها هزار رشته کوچک در حلقه: دستهبندیشان کنید
پرسشهای متداول
چگونه بفهمم تجزیه گلوگاه است یا رندر؟
درخواست، خواندن متن، JSON.parse و رندر را جدا با performance.now() زمانسنجی کنید و بزرگترین مرحله را گلوگاه واقعی بدانید. مرورگرهای مدرن ۱ مگابایت را تقریباً در ۵ تا ۱۵ میلیثانیه و ۱۰ مگابایت را در ۸۰ تا ۱۵۰ میلیثانیه تجزیه میکنند، پس payload ده مگابایتی که دو ثانیه طول میکشد بهندرت مشکل JSON.parse است.
چرا تعویض کتابخانه معمولاً کمک نمیکند؟
JSON.parse از قبل بومی و سریع است؛ بیشتر «تجزیه کند» از تجزیه مکرر یا رندر دهها هزار گره یکجا میآید. تعویض کتابخانه ۱۰ تا ۳۰ درصد میخرد، در حالی که حذف یک تجزیه کامل اغلب نصف را صرفهجویی میکند.
آیا باید تجزیه را به Web Worker منتقل کنم؟
وقتی تجزیه رشته اصلی را مسدود میکند و صفحه قفل میشود یا انیمیشنها فریم از دست میدهند آن را به worker ببرید. متن خام را بفرستید نه شیء تجزیهشده، وگرنه کلون ساختاری postMessage هزینه را دو برابر میکند.