রেন্ডারিংএনজি ডিপ-ডাইভ: লেআউটএনজি

ইয়ান কিলপ্যাট্রিক
Ian Kilpatrick
কোজি ইশি
Koji Ishi

আমি ইয়ান কিলপ্যাট্রিক, কোজি ইশির সাথে ব্লিঙ্ক লেআউট টিমের একজন ইঞ্জিনিয়ারিং লিড। ব্লিঙ্ক টিমে কাজ করার আগে, আমি একজন ফ্রন্ট-এন্ড ইঞ্জিনিয়ার ছিলাম (Google এর আগে "ফ্রন্ট-এন্ড ইঞ্জিনিয়ার" এর ভূমিকা ছিল), Google ডক্স, ড্রাইভ এবং Gmail-এর মধ্যে বৈশিষ্ট্য তৈরি করা। প্রায় পাঁচ বছর সেই ভূমিকায় থাকার পর আমি ব্লিঙ্ক টিমে একটি বড় জুয়া খেলা শুরু করেছিলাম, কার্যকরীভাবে চাকরিতে C++ শিখেছিলাম, এবং ব্যাপক জটিল ব্লিঙ্ক কোডবেসে র‌্যাম্প আপ করার চেষ্টা করেছিলাম। আজও, আমি এটির একটি অপেক্ষাকৃত ছোট অংশ বুঝতে পারি। এই সময়ের মধ্যে আমাকে দেওয়া সময়ের জন্য আমি কৃতজ্ঞ। আমার আগে "ব্রাউজার প্রকৌশলী" হওয়ার জন্য অনেক "পুনরুদ্ধার করা ফ্রন্ট-এন্ড ইঞ্জিনিয়ার" এর মাধ্যমে আমি সান্ত্বনা পেয়েছি।

ব্লিঙ্ক দলে থাকাকালীন আমার পূর্ব অভিজ্ঞতা আমাকে ব্যক্তিগতভাবে নির্দেশিত করেছে। একজন ফ্রন্ট-এন্ড ইঞ্জিনিয়ার হিসাবে আমি ক্রমাগত ব্রাউজারের অসঙ্গতি, পারফরম্যান্স সমস্যা, রেন্ডারিং বাগ এবং অনুপস্থিত বৈশিষ্ট্যগুলির মধ্যে পড়েছি। লেআউটএনজি আমার জন্য ব্লিঙ্কের লেআউট সিস্টেমের মধ্যে এই সমস্যাগুলিকে পদ্ধতিগতভাবে সমাধান করতে সাহায্য করার একটি সুযোগ ছিল এবং এটি বছরের পর বছর ধরে অনেক প্রকৌশলীর প্রচেষ্টার যোগফলকে প্রতিনিধিত্ব করে।

এই পোস্টে, আমি ব্যাখ্যা করব কিভাবে এই ধরনের একটি বৃহৎ স্থাপত্য পরিবর্তন বিভিন্ন ধরনের বাগ এবং কর্মক্ষমতা সমস্যা কমাতে এবং প্রশমিত করতে পারে।

লেআউট ইঞ্জিন আর্কিটেকচারের 30,000 ফুট ভিউ

পূর্বে, ব্লিঙ্কের লেআউট ট্রি ছিল যাকে আমি "পরিবর্তনযোগ্য গাছ" হিসাবে উল্লেখ করব।

নিম্নলিখিত টেক্সটে বর্ণিত হিসাবে গাছ দেখায়.

লেআউট ট্রির প্রতিটি অবজেক্টে ইনপুট তথ্য থাকে, যেমন অভিভাবকের দ্বারা আরোপিত উপলব্ধ আকার, যেকোনো ফ্লোটের অবস্থান এবং আউটপুট তথ্য, উদাহরণস্বরূপ, বস্তুর চূড়ান্ত প্রস্থ এবং উচ্চতা বা এর x এবং y অবস্থান।

এই বস্তুগুলি রেন্ডারগুলির মধ্যে চারপাশে রাখা হয়েছিল। যখন শৈলীতে একটি পরিবর্তন ঘটে, তখন আমরা সেই বস্তুটিকে নোংরা হিসাবে চিহ্নিত করেছিলাম এবং একইভাবে গাছের মধ্যে তার সমস্ত পিতামাতাকে। যখন রেন্ডারিং পাইপলাইনের লেআউট পর্বটি চালানো হয়, তখন আমরা গাছটি পরিষ্কার করব, যে কোনও নোংরা বস্তুকে হাঁটব, তারপর সেগুলিকে পরিষ্কার অবস্থায় পেতে লেআউটটি চালাব।

আমরা দেখেছি যে এই আর্কিটেকচারের ফলে অনেক ধরণের সমস্যা হয়েছে, যা আমরা নীচে বর্ণনা করব। কিন্তু প্রথমে, আসুন পিছিয়ে যাই এবং লেআউটের ইনপুট এবং আউটপুটগুলি কী তা বিবেচনা করি।

এই ট্রির একটি নোডে লেআউট চালানো ধারণাগতভাবে "স্টাইল প্লাস DOM" নেয়, এবং প্যারেন্ট লেআউট সিস্টেম (গ্রিড, ব্লক বা ফ্লেক্স) থেকে যেকোন প্যারেন্ট সীমাবদ্ধতা, লেআউট সীমাবদ্ধতা অ্যালগরিদম চালায় এবং একটি ফলাফল তৈরি করে।

ধারণাগত মডেল পূর্বে বর্ণিত.

আমাদের নতুন স্থাপত্য এই ধারণাগত মডেলকে আনুষ্ঠানিক করে তোলে। আমাদের কাছে এখনও লেআউট ট্রি আছে, কিন্তু লেআউটের ইনপুট এবং আউটপুটগুলি ধরে রাখতে এটি প্রাথমিকভাবে ব্যবহার করুন। আউটপুটের জন্য, আমরা একটি সম্পূর্ণ নতুন, অপরিবর্তনীয় বস্তু তৈরি করি যাকে ফ্র্যাগমেন্ট ট্রি বলা হয়।

টুকরো গাছ।

ক্রমবর্ধমান বিন্যাসের জন্য পূর্ববর্তী গাছের বড় অংশ পুনরায় ব্যবহার করার জন্য কীভাবে এটি ডিজাইন করা হয়েছে তা বর্ণনা করে আমি পূর্বে অপরিবর্তনীয় টুকরো গাছটিকে কভার করেছি।

উপরন্তু, আমরা প্যারেন্ট সীমাবদ্ধতা বস্তু সংরক্ষণ করি যা সেই খণ্ডটি তৈরি করেছে। আমরা এটিকে একটি ক্যাশে কী হিসাবে ব্যবহার করি যা আমরা নীচে আরও আলোচনা করব।

ইনলাইন (টেক্সট) লেআউট অ্যালগরিদম নতুন অপরিবর্তনীয় আর্কিটেকচারের সাথে মেলে আবার লেখা হয়েছে। এটি কেবল ইনলাইন লেআউটের জন্য অপরিবর্তনীয় ফ্ল্যাট তালিকা উপস্থাপনা তৈরি করে না, বরং দ্রুত রিলেআউটের জন্য অনুচ্ছেদ-স্তরের ক্যাশিং, উপাদান এবং শব্দ জুড়ে ফন্ট বৈশিষ্ট্যগুলি প্রয়োগ করার জন্য আকার-প্রতি-অনুচ্ছেদ, আইসিইউ ব্যবহার করে একটি নতুন ইউনিকোড দ্বিমুখী অ্যালগরিদম, অনেক সঠিকতা। সংশোধন, এবং আরো.

লেআউট বাগ ধরনের

লেআউট বাগগুলি বিস্তৃতভাবে বলতে গেলে চারটি আলাদা বিভাগে পড়ে, প্রতিটির মূল কারণগুলি আলাদা।

যথার্থতা

যখন আমরা রেন্ডারিং সিস্টেমে বাগ সম্পর্কে চিন্তা করি, আমরা সাধারণত সঠিকতা সম্পর্কে চিন্তা করি, উদাহরণস্বরূপ: "ব্রাউজার A-এর X আচরণ আছে, যখন ব্রাউজার B এর Y আচরণ আছে", বা "ব্রাউজার A এবং B উভয়ই ভেঙে গেছে"। পূর্বে আমরা আমাদের অনেক সময় ব্যয় করতাম এবং এই প্রক্রিয়ায় আমরা ক্রমাগত সিস্টেমের সাথে লড়াই করছিলাম। একটি সাধারণ ব্যর্থতা মোড ছিল একটি বাগ-এর জন্য খুব লক্ষ্যযুক্ত ফিক্স প্রয়োগ করা, কিন্তু কয়েক সপ্তাহ পরে আমরা সিস্টেমের অন্য (আপাতদৃষ্টিতে সম্পর্কহীন) অংশে একটি রিগ্রেশন সৃষ্টি করেছি।

পূর্ববর্তী পোস্টে বর্ণিত হিসাবে, এটি একটি খুব ভঙ্গুর সিস্টেমের একটি চিহ্ন. লেআউটের জন্য বিশেষভাবে, আমাদের কোনো ক্লাসের মধ্যে একটি পরিষ্কার চুক্তি ছিল না, যার ফলে ব্রাউজার ইঞ্জিনিয়ারদের সেই অবস্থার উপর নির্ভর করতে হয় যা তাদের উচিত নয়, বা সিস্টেমের অন্য অংশ থেকে কিছু মান ভুল ব্যাখ্যা করা।

একটি উদাহরণ হিসাবে, এক পর্যায়ে আমাদের ফ্লেক্স লেআউট সম্পর্কিত এক বছরেরও বেশি সময় ধরে প্রায় 10টি বাগগুলির একটি চেইন ছিল৷ প্রতিটি ফিক্স সিস্টেমের অংশে একটি শুদ্ধতা বা কর্মক্ষমতা সমস্যা সৃষ্টি করে, যার ফলে আরেকটি বাগ দেখা দেয়।

এখন যেহেতু LayoutNG লেআউট সিস্টেমের সমস্ত উপাদানগুলির মধ্যে চুক্তিকে স্পষ্টভাবে সংজ্ঞায়িত করে, আমরা দেখতে পেয়েছি যে আমরা অনেক বেশি আত্মবিশ্বাসের সাথে পরিবর্তনগুলি প্রয়োগ করতে পারি৷ এছাড়াও আমরা চমৎকার ওয়েব প্ল্যাটফর্ম টেস্ট (WPT) প্রকল্প থেকে অনেক উপকৃত হই, যা একাধিক পক্ষকে একটি সাধারণ ওয়েব টেস্ট স্যুটে অবদান রাখতে দেয়।

আজ আমরা দেখতে পাই যে যদি আমরা আমাদের স্থিতিশীল চ্যানেলে একটি বাস্তব রিগ্রেশন প্রকাশ করি, তবে এটি সাধারণত WPT সংগ্রহস্থলে কোনো সংশ্লিষ্ট পরীক্ষা নেই এবং উপাদান চুক্তির ভুল বোঝাবুঝির ফলে হয় না। আরও, আমাদের বাগফিক্স নীতির অংশ হিসাবে, আমরা সর্বদা একটি নতুন WPT পরীক্ষা যোগ করি, এটি নিশ্চিত করতে সাহায্য করে যে কোনো ব্রাউজার যেন একই ভুল আবার না করে।

অধীন অবৈধ

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

নিচে বর্ণিত লেআউট মোডের সাথে এটি খুবই সাধারণ (চূড়ান্ত লেআউট অবস্থা নির্ধারণ করতে দুইবার লেআউট ট্রি হাঁটা)। পূর্বে আমাদের কোড দেখতে হবে:

if (/* some very complicated statement */) {
  child->ForceLayout();
}

এই ধরনের বাগের জন্য একটি সংশোধন সাধারণত হবে:

if (/* some very complicated statement */ ||
    /* another very complicated statement */) {
  child->ForceLayout();
}

এই ধরনের সমস্যার জন্য একটি সমাধান সাধারণত একটি গুরুতর কর্মক্ষমতা রিগ্রেশনের কারণ হবে, (নীচে অত্যধিক-অবৈধতা দেখুন), এবং সঠিক হওয়ার জন্য খুব সূক্ষ্ম ছিল।

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

এই ডিফিং কোডের সংশোধনগুলি সাধারণত সহজ, এবং এই স্বাধীন বস্তুগুলি তৈরি করার সরলতার কারণে সহজেই একক-পরীক্ষাযোগ্য

একটি নির্দিষ্ট প্রস্থ এবং শতাংশ প্রস্থের চিত্র তুলনা করা।
একটি নির্দিষ্ট প্রস্থ/উচ্চতা উপাদান এটিকে প্রদত্ত উপলব্ধ-আকার বাড়ে কিনা তা বিবেচনা করে না, তবে শতাংশ-ভিত্তিক প্রস্থ/উচ্চতা করে। উপলব্ধ-আকারটি পিতামাতার সীমাবদ্ধতা অবজেক্টে উপস্থাপিত হয়, এবং ডিফিং অ্যালগরিদমের অংশ হিসাবে এই অপ্টিমাইজেশনটি সম্পাদন করবে।

উপরের উদাহরণের জন্য ভিন্ন কোড হল:

if (width.IsPercent()) {
  if (old_constraints.WidthPercentageSize() 
    != new_constraints.WidthPercentageSize())
   return kNeedsLayout;
}
if (height.IsPercent()) {
  if (old_constraints.HeightPercentageSize() 
    != new_constraints.HeightPercentageSize())
   return kNeedsLayout;
}

হিস্টেরেসিস

এই শ্রেণীর বাগগুলি আন্ডার-অবৈধকরণের অনুরূপ। মূলত, পূর্ববর্তী সিস্টেমে এটি নিশ্চিত করা অবিশ্বাস্যভাবে কঠিন ছিল যে লেআউটটি অদম্য ছিল-অর্থাৎ, একই ইনপুটগুলির সাথে লেআউটটি পুনরায় চালানোর ফলে একই আউটপুট হয়েছিল।

নীচের উদাহরণে আমরা কেবল দুটি মানের মধ্যে একটি সিএসএস প্রপার্টি পরিবর্তন করছি। যাইহোক এটি একটি "অসীমভাবে ক্রমবর্ধমান" আয়তক্ষেত্রে পরিণত হয়।

ভিডিও এবং ডেমো Chrome 92 এবং তার নিচের একটি হিস্টেরেসিস বাগ দেখায়। এটি Chrome 93 এ স্থির করা হয়েছে।

আমাদের পূর্ববর্তী পরিবর্তনযোগ্য গাছের সাথে, এই জাতীয় বাগগুলি প্রবর্তন করা অবিশ্বাস্যভাবে সহজ ছিল। যদি কোডটি ভুল সময় বা পর্যায়ে একটি বস্তুর আকার বা অবস্থান পড়ার ভুল করে থাকে (যেমন আমরা পূর্ববর্তী আকার বা অবস্থান "সাফ" করিনি উদাহরণস্বরূপ), আমরা অবিলম্বে একটি সূক্ষ্ম হিস্টেরেসিস বাগ যোগ করব। এই বাগগুলি সাধারণত পরীক্ষায় উপস্থিত হয় না কারণ বেশিরভাগ পরীক্ষা একটি একক লেআউট এবং রেন্ডারের উপর ফোকাস করে। এমনকি আরও গুরুত্বপূর্ণভাবে, আমরা জানতাম যে কিছু লেআউট মোড সঠিকভাবে কাজ করার জন্য এই হিস্টেরেসিসের কিছু প্রয়োজন ছিল। আমাদের বাগ ছিল যেখানে আমরা একটি লেআউট পাস সরানোর জন্য একটি অপ্টিমাইজেশান সঞ্চালন করব, কিন্তু সঠিক আউটপুট পেতে লেআউট মোডের দুটি পাসের প্রয়োজন হওয়ায় একটি "বাগ" প্রবর্তন করুন৷

একটি গাছ পূর্ববর্তী পাঠে বর্ণিত সমস্যাগুলি প্রদর্শন করছে৷
পূর্ববর্তী লেআউট ফলাফলের তথ্যের উপর নির্ভর করে, অ-অদম্য লেআউটের ফলাফল

LayoutNG এর সাথে, যেহেতু আমাদের কাছে সুস্পষ্ট ইনপুট এবং আউটপুট ডেটা-স্ট্রাকচার রয়েছে, এবং পূর্ববর্তী অবস্থায় অ্যাক্সেস করা অনুমোদিত নয়, আমরা লেআউট সিস্টেম থেকে এই শ্রেণীর বাগকে বিস্তৃতভাবে প্রশমিত করেছি।

ওভার-অবৈধতা এবং কর্মক্ষমতা

এটি বাগগুলির আন্ডার-অবৈধকরণ শ্রেণীর সরাসরি বিপরীত। প্রায়ই একটি আন্ডার-অবৈধ বাগ ফিক্স করার সময় আমরা একটি কর্মক্ষমতা ক্লিফ ট্রিগার করব।

আমাদের প্রায়ই পারফরম্যান্সের চেয়ে সঠিকতার পক্ষে কঠিন পছন্দ করতে হয়েছিল। পরবর্তী বিভাগে আমরা কীভাবে এই ধরণের পারফরম্যান্স সমস্যাগুলিকে প্রশমিত করেছি তার গভীরে ডুব দেব।

দুই-পাস লেআউট এবং কর্মক্ষমতা ক্লিফের উত্থান

ফ্লেক্স এবং গ্রিড লেআউট ওয়েবে লেআউটের অভিব্যক্তিতে একটি পরিবর্তনের প্রতিনিধিত্ব করে। যাইহোক, এই অ্যালগরিদমগুলি তাদের আগে আসা ব্লক লেআউট অ্যালগরিদম থেকে মৌলিকভাবে আলাদা ছিল।

ব্লক লেআউট (প্রায় সব ক্ষেত্রেই) শুধুমাত্র ইঞ্জিনকে তার সমস্ত বাচ্চাদের ঠিক একবার লেআউট করতে হবে। এটি পারফরম্যান্সের জন্য দুর্দান্ত, তবে ওয়েব ডেভেলপারদের মতো অভিব্যক্তিপূর্ণ হয় না।

উদাহরণস্বরূপ, প্রায়শই আপনি চান যে সমস্ত শিশুর আকার বড় আকারে প্রসারিত হোক। এটি সমর্থন করার জন্য, পিতামাতার বিন্যাস (ফ্লেক্স বা গ্রিড) প্রতিটি শিশু কত বড় তা নির্ধারণ করতে একটি পরিমাপ পাস সম্পাদন করবে, তারপরে সমস্ত শিশুকে এই আকারে প্রসারিত করার জন্য একটি লেআউট পাস। এই আচরণটি ফ্লেক্স এবং গ্রিড লেআউট উভয়ের জন্যই ডিফল্ট।

বাক্সের দুটি সেট, প্রথমটি পরিমাপ পাসে বাক্সগুলির অন্তর্নিহিত আকার দেখায়, দ্বিতীয়টি লেআউটে সমস্ত সমান উচ্চতা।

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

এক, দুই, এবং তিন-পাস লেআউট ক্যাপশনে ব্যাখ্যা করা হয়েছে।
উপরের ছবিতে, আমাদের তিনটি <div> উপাদান রয়েছে। একটি সাধারণ ওয়ান-পাস লেআউট (ব্লক লেআউটের মতো) তিনটি লেআউট নোড (জটিলতা O(n)) পরিদর্শন করবে। তবে একটি দুই-পাস লেআউটের জন্য (যেমন ফ্লেক্স বা গ্রিড), এটি সম্ভাব্যভাবে এই উদাহরণের জন্য O(2 n ) ভিজিটের জটিলতার কারণ হতে পারে।
লেআউট সময়ের সূচকীয় বৃদ্ধি দেখানো গ্রাফ।
এই চিত্র এবং ডেমো গ্রিড লেআউট সহ একটি সূচকীয় বিন্যাস দেখায়। নতুন আর্কিটেকচারে গ্রিড সরানোর ফলে Chrome 93-এ ​​এটি ঠিক করা হয়েছে

পূর্বে আমরা এই ধরণের পারফরম্যান্স ক্লিফের সাথে লড়াই করার জন্য ফ্লেক্স এবং গ্রিড লেআউটে খুব নির্দিষ্ট ক্যাশে যুক্ত করার চেষ্টা করব। এটি কাজ করেছে (এবং আমরা ফ্লেক্সের সাথে অনেক দূর এগিয়েছি), কিন্তু ক্রমাগত আন্ডার এবং ওভার অবৈধ বাগগুলির সাথে লড়াই করছিলাম।

LayoutNG আমাদের লেআউটের ইনপুট এবং আউটপুট উভয়ের জন্য সুস্পষ্ট ডেটা স্ট্রাকচার তৈরি করতে দেয় এবং এর উপরে আমরা পরিমাপ এবং লেআউট পাসের ক্যাশে তৈরি করেছি। এটি জটিলতাকে O(n) তে ফিরিয়ে আনে, যার ফলে ওয়েব ডেভেলপারদের জন্য অনুমানযোগ্যভাবে রৈখিক কর্মক্ষমতা দেখা যায়। যদি কখনও এমন একটি ঘটনা ঘটে যেখানে একটি লেআউট থ্রি-পাস লেআউট করছে আমরা কেবল সেই পাসটিকেও ক্যাশে করব। এটি ভবিষ্যতে আরও উন্নত লেআউট মোডগুলিকে নিরাপদে প্রবর্তন করার সুযোগগুলি খুলতে পারে- রেন্ডারিংএনজি মৌলিকভাবে বোর্ড জুড়ে কীভাবে এক্সটেনসিবিলিটি আনলক করে তার একটি উদাহরণ। কিছু ক্ষেত্রে গ্রিড লেআউটের জন্য তিন-পাস লেআউটের প্রয়োজন হতে পারে, কিন্তু এই মুহূর্তে অত্যন্ত বিরল।

আমরা দেখতে পাই যে যখন ডেভেলপাররা বিশেষভাবে লেআউট নিয়ে পারফরম্যান্সের সমস্যায় পড়ে, তখন এটি সাধারণত পাইপলাইনের লেআউট পর্যায়ের কাঁচা থ্রুপুটের পরিবর্তে একটি সূচকীয় লেআউট টাইম বাগের কারণে হয়। যদি একটি ছোট ক্রমবর্ধমান পরিবর্তন (একটি উপাদান একটি একক CSS বৈশিষ্ট্য পরিবর্তন করে) একটি 50-100ms লেআউটে পরিণত হয়, এটি সম্ভবত একটি সূচকীয় লেআউট বাগ।

সংক্ষেপে

লেআউট একটি ব্যাপকভাবে জটিল এলাকা, এবং আমরা ইনলাইন লেআউট অপ্টিমাইজেশানের মতো সব ধরণের আকর্ষণীয় বিবরণ কভার করিনি (আসলে কীভাবে পুরো ইনলাইন এবং টেক্সট সাব-সিস্টেম কাজ করে), এবং এমনকি এখানে যে ধারণার কথা বলা হয়েছে তা সত্যিই শুধুমাত্র পৃষ্ঠকে স্ক্র্যাচ করেছে, এবং অনেক বিবরণ উপর glossed. যাইহোক, আশা করি আমরা দেখিয়েছি কিভাবে পদ্ধতিগতভাবে একটি সিস্টেমের আর্কিটেকচার উন্নত করা দীর্ঘমেয়াদে আউটসাইজ লাভের দিকে পরিচালিত করতে পারে।

যে বলে, আমরা জানি আমাদের সামনে এখনও অনেক কাজ বাকি আছে। আমরা সমস্যাগুলির ক্লাস (পারফরম্যান্স এবং সঠিকতা উভয়ই) সম্পর্কে সচেতন যেগুলি আমরা সমাধান করার জন্য কাজ করছি, এবং CSS-এ নতুন লেআউট বৈশিষ্ট্যগুলি নিয়ে উত্তেজিত। আমরা বিশ্বাস করি LayoutNG-এর স্থাপত্য এই সমস্যাগুলিকে নিরাপদ এবং মসৃণ করে তোলে।

উনা ক্র্যাভেটসের একটি ছবি (আপনি জানেন কোনটি!)