JSON Toolkit

বড় JSON ট্রি কেন আটকে যায়: ভার্চুয়াল স্ক্রলিং ও কোলাপ্স কৌশল

সংক্ষেপে: আটকে যাওয়া শুরু হয় DOM নোড তৈরির সময়, স্ক্রল করার সময় নয়। কোলাপ্স-প্রথম রেন্ডারিং, ভার্চুয়াল লিস্ট, সার্চ হাইলাইট ও Worker সীমানা — মেট্রিকসহ।

উন্নত~10 মিনিট পড়াপ্রকাশ 2026-10-31আপডেট 2026-10-31
JSON ভিউয়ারের জন্য ভার্চুয়াল স্ক্রলিং ও কোলাপ্স কৌশল

মূল কথা: "ধীর"-কে পার্সিং, নোড তৈরি, লেআউট ও পেইন্ট, এবং ইন্টারঅ্যাকশনে ভাগ করে প্রতিটি ধাপ মাপুন। এই ক্রমে বাস্তবায়ন করুন — ডিফল্টে কোলাপ্স, তারপর ভার্চুয়াল লিস্ট, তারপর গণনা Worker-এ সরানো, আর হাইলাইটিং দৃশ্যমান সারিতে সীমিত করা। কোলাপ্স না করে সোজা ভার্চুয়াল লিস্টে গেলে কেবল দৃশ্যমান সেট ছোট হয়; পূর্ণ-ট্রি পুনর্গণনার খরচ তবু থাকে।

আটকে যাওয়া সাধারণত ওই ৫MB-র জন্য নয়, বরং ওই ৫MB-র জন্য আপনি যে লক্ষ লক্ষ DOM নোড বানিয়েছেন তার জন্য আসে।

১. "ধীর"-কে চার ধাপে ভাগ করুন

ব্যবহারকারী "খোলার সময় জমে যায়" বললে সমস্যা চারটি সম্পূর্ণ ভিন্ন ধাপে থাকতে পারে, প্রতিটির প্রতিকার আলাদা:

ধাপ সাধারণ ট্রিগার বোঝার থ্রেশহোল্ড প্রধান খরচ
পার্স ও অবজেক্ট গঠন ফাইল খোলা, টেক্সট পেস্ট ৫০ms-এর বেশি যেকোনো কাজ স্ট্রিং স্ক্যান, অবজেক্ট গ্রাফ গঠন
DOM নোড তৈরি একবারে পুরো ট্রি রেন্ডার কয়েক হাজার নোড এলিমেন্ট, টেক্সট নোড, স্টাইল অবজেক্ট বরাদ্দ
লেআউট ও পেইন্ট প্রথম প্রদর্শন, স্ক্রলিং ১৬.৭ms-এর বেশি যেকোনো ফ্রেম জ্যামিতি, রিফ্লো, রিপেইন্ট
ইন্টারঅ্যাকশন সাড়া এক্সপ্যান্ড, কোলাপ্স, সার্চ ১০০ms-এর বেশি দেরি মনে হয় পুনরায় ফ্ল্যাটেনিং ও পুনরায় রেন্ডার

ব্রাউজার মেইন থ্রেড একবারে একটি কাজ করে। যেকোনো ধাপ এটিকে ৫০ms-এর বেশি নিলে স্ক্রলিং ও টাইপিং ফ্রেম ফেলে; পরপর কয়েকটি এমন কাজ হলে পেজ মৃত দেখায়। তাই প্রথম অপ্টিমাইজেশন requestAnimationFrame নয়; কোন ধাপ আসলে সময় খরচ করছে তা মাপা।

২. নোড সংখ্যাই প্রকৃত শত্রু

ট্রি ভিউয়ার নকশা অনুযায়ী নোড সংখ্যা গুণ করে। একটি JSON লাইন সাধারণত "ইনডেন্ট + কি + কোলন + মান + কমা + শেভরন" হয়ে যায়, তাই রক্ষণশীল অনুমান প্রতি লাইনে ৩–৬ DOM নোড:

ফাইল আকার আনুমানিক লাইন ট্রি-ভিউ DOM নোড (অনুমান) একবারে রেন্ডার কেমন হয়
১০০ KB ২,৫০০ ১০,০০০ সাধারণত সহনীয়
১ MB ২৫,০০০ ১,০০,০০০ স্পষ্ট আটকে যায়, হয়তো কয়েক সেকেন্ড ফাঁকা স্ক্রিন
৫ MB ১,২৫,০০০ ৫,০০,০০০ প্রায় নিশ্চিত অপ্রতিক্রিয়াশীল
২০ MB ৫,০০,০০০ ২০ লক্ষেরও বেশি মেমরি ও লেআউট — দুটোই ভেঙে পড়ে

প্রতিটি এলিমেন্ট কয়েক ডজন বাইটের বেশি অবজেক্ট: এটি স্টাইল নিয়ম, লেআউট বক্স ও পেইন্ট নির্দেশ বহন করে। তৈরি হওয়ার পর নোড লেআউট ও স্টাইল কাজে খরচ করে, এমনকি পরে কোলাপ্সড প্যারেন্ট তাকে লুকালেও, যতক্ষণ সত্যিই সরানো না হয়। "সব রেন্ডার করো, তারপর লুকাও" অপ্টিমাইজেশন নয়; এটি কেবল খরচ পরের রিফ্লোতে ফেলে দেয়।

৩. আগে কোলাপ্স, তারপর ভার্চুয়ালাইজ

ভার্চুয়াল স্ক্রলিং "অতিরিক্ত দৃশ্যমান সারি" সমাধান করে। কোলাপ্স সমাধান করে "আমাদের আদৌ এত সারি দেখা উচিত নয়।" ক্রম গুরুত্বপূর্ণ: ডিফল্টে এক্সপ্যান্ড করা লক্ষ-লাইনের ডকুমেন্টে নিখুঁত ভার্চুয়াল লিস্টও ব্যবহারকারী "সব কোলাপ্স" চাপলে পুরো ট্রি পুনর্গণনা করতে বাধ্য হয়।

একটি কার্যকর কোলাপ্স কৌশল:

  • ডিফল্টে কেবল প্রথম দুই স্তর এক্সপ্যান্ড করুন। রুট ও তার তাৎক্ষণিক ফিল্ড দেখা যায়; গভীর স্তর items: Array(12000)-এর মতো সারসংক্ষেপ দেখায়;
  • সারসংক্ষেপে টাইপ ও গণনা রাখুন। "ফিল্ড-নাম ঠিক আছে কি" যাচাই করা ব্যবহারকারীর দশ হাজার রেকর্ড সাধারণত দরকার হয় না;
  • প্রতি সাবট্রি সারি ক্যাশ করুন। প্রতিটি এক্সপ্যান্ড করা নোড তার ফ্ল্যাটেন করা সারি অ্যারে রাখে; কোলাপ্সে তা বাদ যায়, আর এক্সপ্যান্ডে কেবল সেই সাবট্রি পুনর্গণনা হয়;
  • প্রতিটি টগলে পুরো ট্রি আবার স্ক্যান করবেন না। ৩,০০০ সারিতে এক্সপ্যান্ড হলে কেবল সেই রেঞ্জ বদলান, চারপাশের সারি অক্ষত রাখুন।
/**
 * Insert a subtree's rows after its parent instead of re-flattening the whole tree.
 * @param rows Current visible row array
 * @param parentIndex Index of the parent row
 * @param childRows Flattened rows of the subtree
 * @returns A new visible row array
 */
function replaceSubtreeRows(
  rows: TreeRow[],
  parentIndex: number,
  childRows: TreeRow[],
): TreeRow[] {
  const nextRows = rows.slice();
  nextRows.splice(parentIndex + 1, 0, ...childRows);
  return nextRows;
}

যে প্যাটার্ন এড়াতে হবে তা হলো "এক এক্সপ্যান্ড, এক পূর্ণ রিলেআউট।" প্রতিটি ক্লিকে পুরো অবজেক্ট গ্রাফ আবার হাঁটলে খরচ ডকুমেন্টের সঙ্গে রৈখিকভাবে বাড়ে। প্রতি-সাবট্রি ক্যাশে থাকলে একক এক্সপ্যান্ডের খরচ কেবল সেই সাবট্রির সমান।

৪. ভার্চুয়াল লিস্ট: কেবল ভিউপোর্ট রেন্ডার করুন

কোলাপ্স সারি সংখ্যা কমানোর পরও বাকি কয়েক হাজার সারি হতে পারে। ভার্চুয়াল লিস্ট কন্টেইনারের উচ্চতা "মোট সারি × নির্দিষ্ট সারি উচ্চতা" করে দেয় আর কেবল ভিউপোর্ট প্লাস উপরে-নিচে ছোট বাফারের জন্য এলিমেন্ট তৈরি করে।

const ROW_HEIGHT = 24;
const OVERSCAN = 8;

/**
 * Compute the row range that the viewport should render.
 * @param rows All visible rows
 * @param scrollTop Current scroll offset of the container
 * @param viewportHeight Visible height of the container
 * @returns Rows to render, the start index, and the vertical offset
 */
function getViewportRows(
  rows: TreeRow[],
  scrollTop: number,
  viewportHeight: number,
): { visibleRows: TreeRow[]; startIndex: number; offsetTop: number } {
  const start = Math.max(0, Math.floor(scrollTop / ROW_HEIGHT) - OVERSCAN);
  const end = Math.min(
    rows.length,
    Math.ceil((scrollTop + viewportHeight) / ROW_HEIGHT) + OVERSCAN,
  );

  const visibleNodes = rows.slice(start, end);
  return {
    visibleRows: visibleNodes,
    startIndex: start,
    offsetTop: start * ROW_HEIGHT,
  };
}

অপরিহার্য সীমাবদ্ধতা:

  • সারির উচ্চতা নির্দিষ্ট হতে হবে। কেবল তখনই scrollTop / ROW_HEIGHT সরাসরি ইনডেক্স দেয়। মোড়ানো সারি অনুমোদন করলে প্রতিটি উচ্চতা মাপা ও ক্যাশ করতে হয়, যা এক মাত্রার জটিলতা ও জিটার যোগ করে;
  • transform বা absolute পজিশনিং দিয়ে অফসেট করুন। স্পেসার এলিমেন্ট দিয়ে কন্টেন্ট নিচে ঠেলবেন না, নাহলে প্রতিটি স্ক্রলে লেআউট বদলায়;
  • স্থিতিশীল কি ব্যবহার করুন। সারিকে অ্যারে ইনডেক্স নয়, পাথ দিয়ে কি করুন, নাহলে একটি সারি এক্সপ্যান্ড করলে তার পরের প্রতিটি সারি রিমাউন্ট হয়;
  • স্ক্রল হ্যান্ডলারে কেবল গণনা করুন। রেন্ডারিং requestAnimationFrame-এ ফেলুন আর ডুপ্লিকেট শিডিউলিং থেকে সাবধান থাকুন;
  • বাফার ছোট রাখুন। দুই পাশে পাঁচ-দশ সারি যথেষ্ট; বাফার দ্বিগুণ করলে DOM নোড ও স্টাইল কাজ দ্বিগুণ।

৮০০ পিক্সেল ভিউপোর্ট ও ২৪ পিক্সেল সারিতে প্রায় ৩৪ সারি দৃশ্যমান, বাফারসহ প্রায় পঞ্চাশ রেন্ডার হয়। অন্তর্নিহিত ডকুমেন্ট এক লক্ষ সারি ধরে রাখতে পারে অথচ DOM ধারাবাহিকভাবে কয়েকশ এলিমেন্টে থাকে, লেআউট খরচ সমতল রেখে।

৫. কোলাপ্স, এক্সপ্যান্ড ও স্ক্রল অ্যাঙ্করিং

সারি ইনডেক্স একমাত্র কোঅর্ডিনেট হয়ে গেলে কয়েকটি ইন্টারঅ্যাকশন বিবরণ ভাঙতে শুরু করে:

  1. ভিউপোর্টের উপরে কোলাপ্স করলে দৃশ্যমান অ্যাঙ্কর সংরক্ষণ করুন। নিচের সারি উপরে সরে যায়; একই কমিটে scrollTop ঠিক না করলে কন্টেন্ট লাফ দেয়। অ্যাঙ্কর সারির পাথ রেকর্ড করুন আর তার নতুন ইনডেক্স দিয়ে স্ক্রল পজিশন ফিরিয়ে দিন।
  2. লাফ দেওয়ার আগে পূর্বপুরুষ এক্সপ্যান্ড করুন। সার্চ গভীর ফিল্ডে হিট করলে আগে প্রতিটি প্যারেন্ট এক্সপ্যান্ড করুন, তারপর লক্ষ্য সারি ইনডেক্স গণনা করুন, তারপর স্ক্রল ও হাইলাইট। প্রথম ধাপ বাদ দিলে লক্ষ্য সারি দৃশ্যমান অ্যারেতেই থাকে না।
  3. কিবোর্ড নেভিগেশন দৃশ্যমান সারি থেকে চালান। উপরে-নিচে সারি ইনডেক্স সরায়; বাঁয়ে-ডানে এক্সপ্যান্ড ও কোলাপ্স। কি হ্যান্ডলারের ভেতরে কখনো পুরো ট্রি হাঁটবেন না।
  4. আপডেট এক ফ্রেমে ব্যাচ করুন। পরপর কয়েক স্তর এক্সপ্যান্ড করলে অ্যারের পরিবর্তন মিলিয়ে একবার রেন্ডার করুন, নাহলে প্রতিটি স্তর পূর্ণ রিফ্লো ঘটায়।

৬. সার্চ ও হাইলাইটিং: একবার গণনা, সামান্য প্রদর্শন

ট্রি ভিউয়ারে সার্চ সবচেয়ে উপেক্ষিত পারফরম্যান্স ফাঁদ। প্রতিটি কীস্ট্রোকে পুরো অবজেক্ট গ্রাফ হাঁটলে ও ফল তালিকা পুনর্গঠন করলে লক্ষ-নোডের ডকুমেন্ট সঙ্গে সঙ্গে জমে যায়।

স্তরভিত্তিক পথ:

  • ইনপুট ১৫০–২৫০ms ডিবাউন্স করুন আর প্রতিটি সার্চে সিকোয়েন্স নম্বর দিন যাতে পুরোনো ফল বাতিল হয়;
  • Worker-এ স্ক্যান করুন। অবজেক্ট গ্রাফ হাঁটা বিশুদ্ধ গণনা, DOM-নির্ভরতা নেই, তাই টাইপিং আটকানো উচিত নয়;
  • কেবল পাথ ও সারি ইনডেক্স রাখুন। প্রতিটি মিলে যাওয়া নোড কপি করবেন না বা হাইলাইট করা HTML আগেই বানাবেন না;
  • কেবল দৃশ্যমান সারি হাইলাইট করুন। ভিউপোর্টে কয়েক ডজন সারি থাকে; রেন্ডারের সময় মিলে যাওয়া পাথ দিয়ে স্টাইল প্রয়োগ করুন;
  • লাফের জন্য "পূর্বপুরুষ এক্সপ্যান্ড, তারপর ইনডেক্স নির্ণয়" পুনরায় ব্যবহার করুন, শেভরনে ক্লিকের একই পথ।

একটি নিরাপত্তা বিবরণ: ট্রি ভিউয়ারে কি ও মান ব্যবহারকারীর ডেটা। সেগুলো থেকে হাইলাইট করা HTML বানালে এস্কেপ দরকার, নাহলে মার্কআপযুক্ত স্ট্রিং XSS হয়ে যায়। JSON ভিউয়ারে সমৃদ্ধ টেক্সট দরকার নেই, তাই টেক্সট নোড প্লাস ক্লাস-নাম — দুই দিকেই নিরাপদ ও দ্রুত।

৭. সিনট্যাক্স হাইলাইটিং: CodeMirror ও Monaco ভিন্ন টুল

ট্রি ভিউ ও টেক্সট এডিটর ভিন্ন রেন্ডারিং মডেল, তাই "কোনটি দ্রুত" সরাসরি তুলনা নয়:

মাত্রা CodeMirror 6 Monaco Editor
পজিশনিং মডুলার এডিটর কোর পূর্ণ IDE এডিটর
রেন্ডারিং ভিউপোর্ট-ভিত্তিক ভিউপোর্ট-ভিত্তিক, তবে মডেল ও ডেকোরেশন ভারী
পার্সিং পরিবর্তিত রেঞ্জে Lezer ইনক্রিমেন্টাল পার্সিং Monarch টোকেনাইজার, লাইন ধরে
বড় ফাইল এক্সটেনশনের উপর নির্ভর; ডিফল্টে হালকা ফিচার-সম্পূর্ণ, বেশি মেমরি ও স্টার্টআপ খরচ
ফোল্ডিং ও সার্চ আলাদা এক্সটেনশন, চাহিদামাফিক লোড বিল্ট-ইন, স্থায়ী ওভারহেডসহ
সাধারণ ফাঁদ অতিরিক্ত এক্সটেনশন খরচ ফিরিয়ে আনে মিনিম্যাপ, স্টিকি স্ক্রল ও স্তূপ করা ডেকোরেশন

দুটি ব্যবহারিক সিদ্ধান্ত:

  • ট্রি ভিউতে পূর্ণ টোকেনাইজার দরকার নেই। কি, স্ট্রিং, সংখ্যা ও বুলিয়ানে সাধারণ টেক্সট নোড ও CSS ক্লাস দিয়ে প্রতিটিতে এক রং দিন; এটি সিনট্যাক্স হাইলাইটিং চালানোর চেয়ে এক মাত্রা কম খরচ;
  • ট্রি ভিউ ও এডিটর একসঙ্গে মাউন্ট করবেন না। এক ডকুমেন্টের দুটি মডেল রাখলে মেমরি দ্বিগুণ; পুরোনো ভিউ লুকানোর বদলে ধ্বংস করুন।

ভিউয়ারের ভেতরে এডিটর সত্যিই লাগলে CodeMirror 6 "রিড-অনলি, বড় ফাইল, লোকাল হাইলাইটিং"-এ মানায়, আর Monaco কমপ্লিশন, ডায়াগনস্টিকস ও মাল্টি-কার্সর সম্পাদনায়। ফিচার তালিকা পড়ার আগে প্রথম-পেইন্ট সময় ও রেসিডেন্ট মেমরি মাপুন। এডিটর ও CLI টুলের গভীর তুলনার জন্য দেখুন এডিটর, কমান্ড-লাইন টুল ও অটোমেশন।

৮. Worker সীমানা: পার্সিং ও সারি গঠন মেইন থ্রেড থেকে সরান

রেন্ডারিং জ্যাঙ্কের বাকি অর্ধেক মেইন থ্রেডে পার্সিং। ১MB-এর বেশি JSON-এ পার্সিং, ফরম্যাটিং ও ফ্ল্যাট-সারি গঠন Web Worker-এ যাওয়া উচিত; মেইন থ্রেড কেবল সারি নেয় ও ভিউপোর্ট পেইন্ট করে।

Worker বিনা খরচের নয়: postMessage structured clone ব্যবহার করে, তাই ৫০MB অবজেক্ট গ্রাফ মেইন থ্রেডে ফেরত পাঠালে দ্বিতীয় কপি তৈরি হয় আর শিখর দ্বিগুণ। সঠিক সীমানা হলো Worker-এর ভেতরে পার্স ও ফ্ল্যাটেন, কেবল রেন্ডারারের দরকারি সারি ফেরত দেওয়া:

worker.onmessage = (event: MessageEvent<{ rows: TreeRow[] }>) => {
  rows = event.data.rows;
  requestAnimationFrame(() => renderViewport());
};

worker.postMessage({ text });

সারি ডেটা এখনও বড় হলে সারিকে সমান্তরাল অ্যারেতে (পাথ, টাইপ, মান-অফসেট) কম্প্রেস করুন, ArrayBuffer-এ রাখুন, আর মালিকানা ট্রান্সফার করুন যাতে মেইন থ্রেড কপির দাম না দেয়। দাম হলো নিজের সিরিয়ালাইজার লেখা, যা কেবল লক্ষ লক্ষ সারিতে লাভজনক।

সীমানার নিয়ম সরল: মেইন থ্রেড কেবল সেই কাজ করবে যা DOM ছুঁতেই হবে। পার্সিং, সার্চ, সর্টিং, ফরম্যাটিং ও ডিফ — সবই সরে যেতে পারে। রেন্ডারিং, স্ক্রলিং, ইনপুট ও ফোকাস মেইন থ্রেডে থাকে, আর প্রতিটি ফ্রেম কাজের বাজেটে ফিট হতে হবে।

৯. মেট্রিকস ও বাস্তবায়নের ক্রম

অপ্টিমাইজেশন "দ্রুত লাগছে" বলে থামতে পারে না। নিচের সেট সোজা গ্রহণযোগ্যতার চেকলিস্টে যেতে পারে:

মেট্রিক লক্ষ্য কীভাবে মাপবেন
প্রথম দৃশ্যমান ফ্রেম ৩০০ms-এর নিচে খোলা থেকে প্রথম পেইন্ট পর্যন্ত performance.now()
লং টাস্ক ৫০ms-এর বেশি কোনোটি নয় PerformanceObserver দিয়ে longtask দেখা
স্ক্রল ফ্রেম সময় স্থিরভাবে ১৬.৭ms-এর নিচে DevTools Performance রেকর্ডিং
ভিউপোর্টে DOM এলিমেন্ট ২,০০০-এর নিচে document.querySelectorAll('*').length
এক্সপ্যান্ড / কোলাপ্স সাড়া ৫০ms-এর নিচে ইন্টারঅ্যাকশনের চারপাশে টাইমস্ট্যাম্প
১,০০,০০০ সারিতে সার্চ Worker-এর ভেতরে ৩০০ms-এর নিচে Worker-এ সময় মাপিয়ে duration ফেরত দিন
রেসিডেন্ট হিপ টেক্সট আকারের ৩ গুণের নিচে DevTools Memory হিপ স্ন্যাপশট

একইভাবে জেনারেট করা ছোট অবজেক্ট নয়, বাস্তব ফাইল দিয়ে মাপুন; ডেটার আকৃতি গুরুত্বপূর্ণ, আর দীর্ঘ স্ট্রিং, গভীর নেস্টিং ও খুব প্রশস্ত অ্যারে ভিন্ন ভিন্ন বক্ররেখা দেয়। অবজেক্ট-গ্রাফ খাতার জন্য দেখুন JSON মেমরি খাতা।

এই ক্রমে বাস্তবায়ন করুন:

  1. বেসলাইন মাপুন: প্রথম-রেন্ডার সময়, নোড সংখ্যা, স্ক্রল ফ্রেম সময়;
  2. ডিফল্টে কোলাপ্স: দুই স্তর এক্সপ্যান্ড, সারসংক্ষেপে টাইপ ও গণনা;
  3. ভার্চুয়াল লিস্ট: নির্দিষ্ট সারি উচ্চতা, স্থিতিশীল কি, ভিউপোর্ট প্লাস ছোট বাফার;
  4. গণনা সরান: পার্সিং, সার্চ ও ফ্ল্যাটেনিং Worker-এ;
  5. হাইলাইটিং সীমিত করুন: কেবল দৃশ্যমান সারিতে স্টাইল, পুরো ট্রি রিপেইন্ট এড়ান;
  6. গার্ডরেল যোগ করুন: থ্রেশহোল্ডের উপরে "প্রথম N সারি দেখান" বা সার্চ ফিল্টার বাধ্যতামূলক করুন।

প্রতিটি ধাপ একটি লক্ষ্য ভাগ করে: একই মুহূর্তে থাকা নোড ও অবজেক্ট কমানো, ব্রাউজারকে তাদের উপর আরও খাটানো নয়। স্তরভিত্তিক কৌশলের পূর্ণ পটভূমি বড় JSON পার্সিং, রেন্ডারিং ও স্ট্রিমিং-এ।

ভার্চুয়াল স্ক্রলিং কি পার্স-সময়ের জ্যাঙ্ক ঠিক করতে পারে?

না। ভার্চুয়াল স্ক্রলিং কেবল DOM নোড কমায়। পার্সিং এখনও মেইন থ্রেডে হলে পেজ তবু আটকে যায়। ১MB-এর বেশি ডকুমেন্টে পার্সিং Worker-এ সরান আর দুই সমস্যাকে আলাদা ধরুন।

সব এক্সপ্যান্ড করা আছে তবু আটকে যায়। কী ভুল?

হয় ভার্চুয়াল লিস্ট আসলে সক্রিয় নয়, নয় প্রতিটি এক্সপ্যান্ড পুরো ট্রি আবার স্ক্যান করে। দেখুন স্ক্রিনের বাইরের সারি এখনও DOM তৈরি করে কি না, আর এক্সপ্যান্ড কেবল আক্রান্ত সাবট্রি পুনর্গণনা করে কি না।

JSON ভিউয়ারের জন্য CodeMirror নাকি Monaco?

রিড-অনলি, বড় ফাইল ও লোকাল হাইলাইটিংয়ে CodeMirror 6-কে অগ্রাধিকার দিন; এর মডুলার, চাহিদামাফিক লোডিং হালকা। কমপ্লিশন, ডায়াগনস্টিকস ও মাল্টি-কার্সর সম্পাদনা দরকার হলে Monaco বাছুন। যেটিই নিন, একই ডকুমেন্টের ট্রি ভিউ ও এডিটর একসঙ্গে মাউন্ট করা এড়ান।

সার্চ লাফের পর স্ক্রল পজিশন ভুল কেন?

সাধারণত ভিউ এক্সপ্যান্ডের আগেই স্ক্রল করেছে বলে। আগে সব পূর্বপুরুষ এক্সপ্যান্ড করুন, তারপর নতুন সারি ইনডেক্স থেকে স্ক্রল পজিশন সেট করুন, আর হাইলাইট সবার শেষে। সারিকে ইনডেক্স নয়, পাথ দিয়ে কি করুন যাতে এক্সপ্যান্ড প্রতিটি ইনডেক্স না সরায়।

সাধারণ প্রশ্ন

আটকে যাওয়া কোন ধাপ থেকে আসছে কীভাবে জানব?

"ধীর"-কে পার্সিং ও অবজেক্ট গঠন, DOM নোড তৈরি, লেআউট ও পেইন্ট, এবং ইন্টারঅ্যাকশন সাড়ায় ভাগ করুন, আর খোলা থেকে প্রথম পেইন্ট পর্যন্ত performance.now() দিয়ে প্রতিটি ধাপ সময় করুন। তারপর PerformanceObserver দিয়ে longtask দেখুন — ৫০ms-এর বেশি যেকোনো কাজ ফ্রেম ফেলে, আর DevTools Performance রেকর্ডিং দেখায় স্ক্রল ফ্রেম সময় ১৬.৭ms-এর নিচে থাকে কি না।

একবারে পুরো ট্রি রেন্ডার করলে স্ক্রিন ফাঁকা হয়ে যায় কেন?

৫MB ডকুমেন্ট প্রায় ১,২৫,০০০ লাইন, আর ট্রি ভিউ সাধারণত প্রতিটি লাইনকে ৩–৬ DOM নোডে বদলায় — একবারে প্রায় ৫,০০,০০০ এলিমেন্ট। প্রতিটি এলিমেন্ট স্টাইল নিয়ম, লেআউট বক্স ও পেইন্ট নির্দেশও বহন করে, তাই পরপর কয়েকটি ৫০ms-এর বেশি মেইন-থ্রেড কাজ পেজকে মৃত দেখায়। কোলাপ্সড প্যারেন্টে লুকানো নোডও লেআউট কাজে খরচ করে, তাই "সব রেন্ডার করো, তারপর লুকাও" অপ্টিমাইজেশন নয়।

Worker থেকে ৫০MB অবজেক্ট গ্রাফ ফেরত পাঠানো উচিত?

না। postMessage structured clone ব্যবহার করে, তাই গ্রহণকারী পক্ষ দ্বিতীয় কপি বানায় আর শিখর দ্বিগুণ হয়। সঠিক সীমানা হলো Worker-এর ভেতরে পার্স ও ফ্ল্যাটেন করে কেবল রেন্ডারারের দরকারি সারি ফেরত দেওয়া; লক্ষ লক্ষ সারিতে সমান্তরাল অ্যারে (পাথ, টাইপ, মান-অফসেট) ArrayBuffer-এ প্যাক করে মালিকানা ট্রান্সফার করতে পারেন।