বড় JSON পার্সিং দ্রুত করা
সংক্ষেপে: ভুল ক্রমে অপ্টিমাইজ করলে প্রতিটি লাইব্রেরি বদল বৃথা। নেটওয়ার্ক, পার্স ও রেন্ডার আলাদা মাপুন, তারপর পার্স কমান, পেললোড ছোট করুন ও স্ট্রিম করুন।

মূল কথা: আগে নেটওয়ার্ক, পার্স ও রেন্ডার আলাদা মাপুন — বেশিরভাগ "ধীর পার্সিং" আসলে ধীর রেন্ডারিং — তারপর ক্রমে সিঁড়ি বেয়ে উঠুন: কম পার্স, ছোট পেললোড, স্ট্রিমিং, 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();
| প্রধান ধাপ | আসল সমস্যা | সমাধান |
|---|---|---|
| নেটওয়ার্ক | পেললোড খুব বড় | ফিল্ড নির্বাচন, পেজিনেশন, কম্প্রেশন |
JSON.parse |
সত্যিই বড় ইনপুট | কম পার্স, স্ট্রিমিং, Worker |
| রেন্ডার | একবারে কয়েক হাজার নোড | ভার্চুয়াল লিস্ট, পেজিং, কোলাপ্সিং |
আধুনিক ব্রাউজার ১MB প্রায় ৫–১৫ms-এ আর ১০MB ৮০–১৫০ms-এ পার্স করে। ১০MB দুই সেকেন্ড নিলে JSON.parse আপনার bottleneck নয়।
ধাপ দুই: কম পার্স করুন
সবচেয়ে সস্তা লাভ, আর সবচেয়ে উপেক্ষিত।
- একই পেললোড বারবার পার্স করা বন্ধ করুন। দশটি কম্পোনেন্ট প্রত্যেকে
JSON.parse(localStorage.getItem(...))কল করলে দশ পার্স। মডিউল স্তরে একবার ক্যাশ করুন। - গভীর কপিতে
JSON.parse(JSON.stringify(x))বন্ধ করুন। এটি ডেটার দ্বিগুণেরও বেশি খরচ করে;structuredCloneকরে না। - মেইন থ্রেডে পার্স করে অবজেক্ট Worker-এ পাঠাবেন না।
postMessageআবার ক্লোন করে। কাঁচা টেক্সট পাঠান আর Worker পার্স করুক। - কম ফিল্ড চান। UI-তে তিনটি প্রপার্টি দরকার হলে API তিনশো পাঠাবে না।
ধাপ তিন: পেললোড ছোট করুন
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-এ রাখুন আর টেক্সট পাঠান, পার্স করা অবজেক্ট নয়, নাহলে structured cloning খরচ দ্বিগুণ করে।
ধাপ ছয়: সবার শেষে ফরম্যাট বদলান
ধারাবাহিকভাবে কয়েক ডজন মেগাবাইট অভ্যন্তরীণ ট্রাফিকে NDJSON স্বাভাবিকভাবে স্ট্রিম করে, আর Protobuf বা MessagePack ছোট ও দ্রুত। দুটোই প্রোটোকল পরিবর্তন, সমন্বয় দরকার।
করবেন না
- JSON
evalকরা: অনিরাপদ আর দ্রুতও নয় - JSON-এ এম্বেড করতে JSON স্ট্রিংফাই করা: আকার দ্বিগুণ
- লুপে লক্ষ লক্ষ ক্ষুদ্র স্ট্রিং পার্স করা: ব্যাচ করুন
সাধারণ প্রশ্ন
পার্সিং নাকি রেন্ডারিং bottleneck তা কীভাবে জানব?
performance.now() দিয়ে রিকোয়েস্ট, টেক্সট পড়া, JSON.parse ও রেন্ডার আলাদা সময় করুন, আর সবচেয়ে বড় ধাপকে আসল bottleneck ধরুন। আধুনিক ব্রাউজার ১MB প্রায় ৫–১৫ms-এ আর ১০MB ৮০–১৫০ms-এ পার্স করে, তাই দুই সেকেন্ড নেওয়া ১০MB পেললোড কদাচিৎ JSON.parse-এর সমস্যা।
লাইব্রেরি বদলানো সাধারণত কাজ করে না কেন?
JSON.parse ইতিমধ্যে নেটিভ ও দ্রুত; বেশিরভাগ "ধীর পার্সিং" আসে বারবার পার্সিং বা একবারে কয়েক হাজার নোড রেন্ডার থেকে। লাইব্রেরি বদলে ১০–৩০% পাওয়া যায়, অথচ একটি পূর্ণ পার্স সরালে প্রায়ই অর্ধেক বাঁচে।
পার্সিং Web Worker-এ সরানো উচিত?
পার্সিং মেইন থ্রেড ব্লক করে পেজ জমে গেলে বা অ্যানিমেশন ফ্রেম ফেললে Worker-এ সরান। পার্স করা অবজেক্ট নয়, কাঁচা টেক্সট পাঠান, নাহলে postMessage structured cloning খরচ দ্বিগুণ করে।