নেক্সট পেইন্টের সাথে মিথস্ক্রিয়া বোঝা (আইএনপি)

1. ভূমিকা

ইন্টারঅ্যাকশন টু নেক্সট পেইন্ট (INP) সম্পর্কে শেখার জন্য একটি ইন্টারেক্টিভ ডেমো এবং কোডল্যাব।

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

পূর্বশর্ত

  • HTML এবং জাভাস্ক্রিপ্ট ডেভেলপমেন্ট সম্পর্কে জ্ঞান।
  • প্রস্তাবিত: INP ডকুমেন্টেশনটি পড়ুন।

তুমি যা শিখো

  • ব্যবহারকারীর মিথস্ক্রিয়ার পারস্পরিক ক্রিয়া এবং সেই মিথস্ক্রিয়াগুলির আপনার পরিচালনা কীভাবে পৃষ্ঠার প্রতিক্রিয়াশীলতাকে প্রভাবিত করে।
  • মসৃণ ব্যবহারকারীর অভিজ্ঞতার জন্য বিলম্ব কীভাবে কমানো এবং দূর করা যায়।

তোমার যা দরকার

  • GitHub থেকে কোড ক্লোন করে npm কমান্ড চালানোর ক্ষমতা সম্পন্ন একটি কম্পিউটার।
  • একটি টেক্সট এডিটর।
  • সমস্ত মিথস্ক্রিয়া পরিমাপ কাজ করার জন্য Chrome এর একটি সাম্প্রতিক সংস্করণ।

2. সেট আপ করুন

কোডটি নিন এবং রান করুন।

কোডটি web-vitals-codelabs সংগ্রহস্থলে পাওয়া যাবে।

  1. আপনার টার্মিনালে রেপো ক্লোন করুন: git clone https://github.com/GoogleChromeLabs/web-vitals-codelabs.git
  2. ক্লোন করা ডিরেক্টরিতে প্রবেশ করুন: cd web-vitals-codelabs/understanding-inp
  3. নির্ভরতা ইনস্টল করুন: npm ci
  4. ওয়েব সার্ভার শুরু করুন: npm run start
  5. আপনার ব্রাউজারে http://localhost:5173/understanding-inp/ দেখুন।

অ্যাপটির ওভারভিউ

পৃষ্ঠার শীর্ষে একটি স্কোর কাউন্টার এবং ইনক্রিমেন্ট বোতাম রয়েছে। প্রতিক্রিয়াশীলতা এবং প্রতিক্রিয়াশীলতার একটি ক্লাসিক ডেমো!

এই কোডল্যাবের ডেমো অ্যাপের একটি স্ক্রিনশট

বোতামের নীচে চারটি পরিমাপ রয়েছে:

  • INP: বর্তমান INP স্কোর, যা সাধারণত সবচেয়ে খারাপ মিথস্ক্রিয়া।
  • মিথস্ক্রিয়া: সাম্প্রতিক মিথস্ক্রিয়ার স্কোর।
  • FPS: পৃষ্ঠার প্রতি সেকেন্ডে প্রধান থ্রেড ফ্রেম।
  • টাইমার: জ্যাঙ্ককে কল্পনা করতে সাহায্য করার জন্য একটি চলমান টাইমার অ্যানিমেশন।

ইন্টারঅ্যাকশন পরিমাপের জন্য FPS এবং টাইমার এন্ট্রিগুলি মোটেও প্রয়োজনীয় নয়। এগুলি কেবল ভিজ্যুয়ালাইজিং রেসপন্সিভিটি আরও সহজ করার জন্য যোগ করা হয়েছে।

চেষ্টা করে দেখো

ইনক্রিমেন্ট বোতামটি ব্যবহার করে ইন্টারঅ্যাক্ট করার চেষ্টা করুন এবং স্কোর বৃদ্ধি দেখুন। প্রতিটি ইনক্রিমেন্টের সাথে কি INP এবং ইন্টারঅ্যাকশন মান পরিবর্তিত হয়?

ব্যবহারকারীর ইন্টারঅ্যাক্ট করার মুহূর্ত থেকে পৃষ্ঠাটি ব্যবহারকারীকে রেন্ডার করা আপডেট দেখানো পর্যন্ত কত সময় লাগে তা INP পরিমাপ করে।

৩. Chrome DevTools এর সাথে মিথস্ক্রিয়া পরিমাপ করা

More Tools > Developer Tools মেনু থেকে DevTools খুলুন , পৃষ্ঠায় ডান ক্লিক করে Inspect নির্বাচন করে , অথবা একটি কীবোর্ড শর্টকাট ব্যবহার করে।

পারফরম্যান্স প্যানেলে যান, যা আপনি মিথস্ক্রিয়া পরিমাপ করতে ব্যবহার করবেন।

অ্যাপের পাশে থাকা DevTools পারফর্মেন্স প্যানেলের একটি স্ক্রিনশট

এরপর, পারফরম্যান্স প্যানেলে একটি ইন্টারঅ্যাকশন ক্যাপচার করুন।

  1. রেকর্ড টিপুন।
  2. পৃষ্ঠাটির সাথে ইন্টারঅ্যাক্ট করুন ( বৃদ্ধি বোতাম টিপুন)।
  3. রেকর্ডিং বন্ধ করো।

ফলস্বরূপ টাইমলাইনে, আপনি একটি ইন্টারঅ্যাকশন ট্র্যাক পাবেন। বাম দিকের ত্রিভুজটিতে ক্লিক করে এটি প্রসারিত করুন।

DevTools পারফর্ম্যান্স প্যানেল ব্যবহার করে একটি ইন্টারঅ্যাকশন রেকর্ড করার একটি অ্যানিমেটেড প্রদর্শন

দুটি ইন্টারঅ্যাকশন দেখা যাচ্ছে। স্ক্রোল করে বা W কী ধরে রেখে দ্বিতীয়টি জুম করুন।

DevTools পারফর্মেন্স প্যানেলের একটি স্ক্রিনশট, প্যানেলে ইন্টারঅ্যাকশনের উপর কার্সার ঘোরানো, এবং ইন্টারঅ্যাকশনের সংক্ষিপ্ত সময় তালিকাভুক্ত একটি টুলটিপ

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

৪. দীর্ঘমেয়াদী ইভেন্ট শ্রোতা

index.js ফাইলটি খুলুন এবং ইভেন্ট লিসেনারের ভিতরে থাকা blockFor ফাংশনটি আনকমেন্ট করুন।

সম্পূর্ণ কোড দেখুন: click_block.html

button.addEventListener('click', () => {
  blockFor(1000);
  score.incrementAndUpdateUI();
});

ফাইলটি সংরক্ষণ করুন। সার্ভার পরিবর্তনটি দেখতে পাবে এবং আপনার জন্য পৃষ্ঠাটি রিফ্রেশ করবে।

পৃষ্ঠাটির সাথে আবার ইন্টারঅ্যাক্ট করার চেষ্টা করুন। ইন্টারঅ্যাকশনগুলি এখন লক্ষণীয়ভাবে ধীর হবে।

পারফর্ম্যান্স ট্রেস

পারফর্মেন্স প্যানেলে আরেকটি রেকর্ডিং নিন এবং দেখুন এটি কেমন দেখাচ্ছে।

পারফর্মেন্স প্যানেলে এক সেকেন্ডের ইন্টারঅ্যাকশন

যা একসময় সংক্ষিপ্ত মিথস্ক্রিয়া ছিল এখন তা সম্পূর্ণ এক সেকেন্ড সময় নেয়।

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

৫. পরীক্ষা: প্রক্রিয়াকরণের সময়কাল

INP-এর উপর প্রভাব দেখতে ইভেন্ট-লিসেনারের কাজ পুনর্বিন্যাস করার উপায়গুলি চেষ্টা করে দেখুন।

প্রথমে UI আপডেট করুন

যদি আপনি js কলের ক্রম পরিবর্তন করেন তাহলে কী হবে—প্রথমে UI আপডেট করুন, তারপর ব্লক করুন?

সম্পূর্ণ কোড দেখুন: ui_first.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
  blockFor(1000);
});

তুমি কি লক্ষ্য করেছো যে UI আগে দেখা যাচ্ছে? অর্ডার কি INP স্কোরকে প্রভাবিত করে?

কোনও পার্থক্য আছে কিনা তা দেখার জন্য একটি ট্রেস নেওয়ার চেষ্টা করুন এবং মিথস্ক্রিয়া পরীক্ষা করে দেখুন।

আলাদা শ্রোতা

যদি আপনি কাজটি আলাদা ইভেন্ট লিসেনারের কাছে স্থানান্তর করেন তাহলে কী হবে? একটি ইভেন্ট লিসেনারের UI আপডেট করুন এবং আলাদা লিসেনারের পৃষ্ঠাটি ব্লক করুন।

সম্পূর্ণ কোড দেখুন: two_click.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
});

button.addEventListener('click', () => {
  blockFor(1000);
});

পারফর্ম্যান্স প্যানেলে এখন কেমন দেখাচ্ছে?

বিভিন্ন ধরণের ইভেন্ট

বেশিরভাগ ইন্টারঅ্যাকশন অনেক ধরণের ইভেন্ট চালু করবে, পয়েন্টার বা কী ইভেন্ট থেকে শুরু করে হোভার, ফোকাস/ব্লার, এবং বিফোরচেঞ্জ এবং বিফোরইনপুটের মতো সিন্থেটিক ইভেন্ট।

অনেক বাস্তব পৃষ্ঠায় বিভিন্ন ঘটনার শ্রোতা থাকে।

ইভেন্ট লিসেনারের জন্য ইভেন্টের ধরণ পরিবর্তন করলে কী হবে? উদাহরণস্বরূপ, click ইভেন্ট লিসেনারের যেকোনো একটির পরিবর্তে pointerup অথবা mouseup ব্যবহার করবেন?

সম্পূর্ণ কোড দেখুন: diff_handlers.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
});

button.addEventListener('pointerup', () => {
  blockFor(1000);
});

কোনও UI আপডেট নেই

ইভেন্ট লিসেনার থেকে UI আপডেট করার কলটি সরিয়ে দিলে কী হবে?

সম্পূর্ণ কোড দেখুন: no_ui.html

button.addEventListener('click', () => {
  blockFor(1000);
  // score.incrementAndUpdateUI();
});

৬. পরীক্ষার ফলাফল প্রক্রিয়াকরণের সময়কাল

পারফর্ম্যান্স ট্রেস: প্রথমে UI আপডেট করুন

সম্পূর্ণ কোড দেখুন: ui_first.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
  blockFor(1000);
});

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

পারফর্মেন্স প্যানেলে এখনও এক সেকেন্ডের ইন্টারঅ্যাকশন

পারফর্ম্যান্স ট্রেস: পৃথক শ্রোতা

সম্পূর্ণ কোড দেখুন: two_click.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
});

button.addEventListener('click', () => {
  blockFor(1000);
});

আবার, কার্যকরীভাবে কোন পার্থক্য নেই। মিথস্ক্রিয়াটি এখনও পুরো এক সেকেন্ড সময় নেয়।

যদি আপনি ক্লিক ইন্টারঅ্যাকশনটি জুম করে দেখেন, তাহলে দেখতে পাবেন যে click ইভেন্টের ফলে দুটি ভিন্ন ফাংশন কল করা হচ্ছে।

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

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

পারফর্ম্যান্স ট্রেস: বিভিন্ন ধরণের ইভেন্ট

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
});

button.addEventListener('pointerup', () => {
  blockFor(1000);
});

এই ফলাফলগুলি খুবই একই রকম। ইন্টারঅ্যাকশনটি এখনও পুরো এক সেকেন্ডের; একমাত্র পার্থক্য হল যে ছোট UI-আপডেট-শুধুমাত্র click লিসেনার এখন ব্লকিং pointerup লিসেনারের পরে চলে।

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

পারফর্ম্যান্স ট্রেস: কোনও UI আপডেট নেই

সম্পূর্ণ কোড দেখুন: no_ui.html

button.addEventListener('click', () => {
  blockFor(1000);
  // score.incrementAndUpdateUI();
});
  • স্কোর আপডেট হয় না, কিন্তু পৃষ্ঠাটি এখনও আপডেট হয়!
  • অ্যানিমেশন, সিএসএস ইফেক্ট, ডিফল্ট ওয়েব কম্পোনেন্ট অ্যাকশন (ফর্ম ইনপুট), টেক্সট এন্ট্রি, টেক্সট হাইলাইটিং সবকিছুই আপডেট হতে থাকে।

এই ক্ষেত্রে বোতামটি একটি সক্রিয় অবস্থায় চলে যায় এবং ক্লিক করলে ফিরে আসে, যার জন্য ব্রাউজার দ্বারা একটি পেইন্ট প্রয়োজন, যার অর্থ এখনও একটি INP আছে।

যেহেতু ইভেন্ট লিসেনার মূল থ্রেডটি এক সেকেন্ডের জন্য ব্লক করে রেখেছিল, ফলে পৃষ্ঠাটি রঙ করা থেকে বিরত ছিল, তবুও ইন্টারঅ্যাকশনটি সম্পূর্ণ এক সেকেন্ড সময় নেয়।

একটি পারফরম্যান্স প্যানেল রেকর্ডিং নিলে দেখা যায় যে ইন্টারঅ্যাকশনটি কার্যত আগেরগুলির মতোই।

পারফর্মেন্স প্যানেলে এখনও এক সেকেন্ডের ইন্টারঅ্যাকশন

ছাড়াইয়া লত্তয়া

যেকোনো ইভেন্ট লিসেনারে চলমান যেকোনো কোড ইন্টারঅ্যাকশন বিলম্বিত করবে।

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

এটা একটা সাধারণ সমস্যা!

পরিশেষে: আপনার কোডটি পেইন্ট ট্রিগার না করার অর্থ এই নয় যে পেইন্টটি ধীর ইভেন্ট লিসেনারের সম্পূর্ণ হওয়ার জন্য অপেক্ষা করবে না।

৭. পরীক্ষা: ইনপুট বিলম্ব

ইভেন্ট লিসেনারের বাইরে দীর্ঘ সময় ধরে চলমান কোড সম্পর্কে কী বলা যায়? উদাহরণস্বরূপ:

  • যদি আপনার দেরিতে লোডিং <script> থাকে যা লোডের সময় এলোমেলোভাবে পৃষ্ঠাটি ব্লক করে দেয়।
  • setInterval এর মতো একটি API কল, যা পর্যায়ক্রমে পৃষ্ঠাটিকে ব্লক করে?

ইভেন্ট লিসেনার থেকে blockFor মুছে setInterval() এ যোগ করার চেষ্টা করুন:

সম্পূর্ণ কোড দেখুন: input_delay.html

setInterval(() => {
  blockFor(1000);
}, 3000);


button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
});

কি হয়?

8. ইনপুট বিলম্ব পরীক্ষার ফলাফল

সম্পূর্ণ কোড দেখুন: input_delay.html

setInterval(() => {
  blockFor(1000);
}, 3000);


button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
});

setInterval ব্লকিং টাস্ক চলাকালীন একটি বোতাম ক্লিক রেকর্ড করার ফলে দীর্ঘস্থায়ী ইন্টারঅ্যাকশন তৈরি হয়, এমনকি ইন্টারঅ্যাকশনের মধ্যেই কোনও ব্লকিং কাজ না হলেও!

এই দীর্ঘস্থায়ী সময়কালগুলিকে প্রায়শই দীর্ঘ কাজ বলা হয়।

DevTools-এ ইন্টারঅ্যাকশনের উপর ঘোরাফেরা করলে, আপনি দেখতে পাবেন যে ইন্টারঅ্যাকশনের সময় এখন মূলত ইনপুট বিলম্বের কারণে, প্রক্রিয়াকরণের সময়কালের কারণে নয়।

DevTools পারফরম্যান্স প্যানেলে এক সেকেন্ডের ব্লকিং টাস্ক, সেই টাস্কের আংশিকভাবে আসা একটি ইন্টারঅ্যাকশন এবং 642 মিলিসেকেন্ডের ইন্টারঅ্যাকশন দেখানো হয়েছে, যার বেশিরভাগই ইনপুট বিলম্বের জন্য দায়ী।

লক্ষ্য করুন, এটি সবসময় ইন্টারঅ্যাকশনগুলিকে প্রভাবিত করে না! যদি আপনি কাজটি চলাকালীন ক্লিক না করেন, তাহলে আপনার ভাগ্য ভালো হতে পারে। এই ধরনের "এলোমেলো" হাঁচি ডিবাগ করা দুঃস্বপ্নের মতো হতে পারে যখন এগুলি কখনও কখনও সমস্যা তৈরি করে।

এগুলো ট্র্যাক করার একটি উপায় হল দীর্ঘ কাজ (অথবা দীর্ঘ অ্যানিমেশন ফ্রেম ) এবং মোট ব্লকিং সময় পরিমাপ করা।

৯. ধীর উপস্থাপনা

এখন পর্যন্ত, আমরা জাভাস্ক্রিপ্টের কর্মক্ষমতা পরীক্ষা করেছি, ইনপুট বিলম্ব বা ইভেন্ট লিসেনারের মাধ্যমে, কিন্তু পরবর্তী পেইন্ট রেন্ডারিংয়ে আর কী প্রভাব ফেলে?

আচ্ছা, দামি ইফেক্ট দিয়ে পেজটি আপডেট করা হচ্ছে!

এমনকি যদি পৃষ্ঠা আপডেট দ্রুত আসে, তবুও ব্রাউজারকে সেগুলি রেন্ডার করার জন্য কঠোর পরিশ্রম করতে হতে পারে!

মূল থ্রেডে:

  • UI ফ্রেমওয়ার্ক যা অবস্থা পরিবর্তনের পরে আপডেট রেন্ডার করতে হবে
  • DOM পরিবর্তন, অথবা অনেক ব্যয়বহুল CSS কোয়েরি নির্বাচক টগল করার ফলে প্রচুর স্টাইল, লেআউট এবং পেইন্ট ট্রিগার হতে পারে।

মূল থ্রেডের বাইরে:

  • GPU প্রভাবগুলিকে শক্তিশালী করতে CSS ব্যবহার করা
  • খুব বড় উচ্চ-রেজোলিউশনের ছবি যোগ করা হচ্ছে
  • জটিল দৃশ্য আঁকতে SVG/ক্যানভাস ব্যবহার করা

ওয়েবে রেন্ডারিংয়ের বিভিন্ন উপাদানের স্কেচ

রেন্ডারিংএনজি

ওয়েবে সাধারণত পাওয়া কিছু উদাহরণ:

  • একটি SPA সাইট যা একটি লিঙ্কে ক্লিক করার পরে সম্পূর্ণ DOM পুনর্নির্মাণ করে, প্রাথমিক ভিজ্যুয়াল প্রতিক্রিয়া প্রদানের জন্য বিরতি না দিয়ে।
  • একটি অনুসন্ধান পৃষ্ঠা যা একটি গতিশীল ব্যবহারকারী ইন্টারফেস সহ জটিল অনুসন্ধান ফিল্টার অফার করে, কিন্তু এটি করার জন্য ব্যয়বহুল শ্রোতাদের চালায়।
  • একটি ডার্ক মোড টগল যা পুরো পৃষ্ঠার জন্য স্টাইল/লেআউট ট্রিগার করে

১০. পরীক্ষা: উপস্থাপনা বিলম্ব

ধীর requestAnimationFrame

requestAnimationFrame() API ব্যবহার করে একটি দীর্ঘ উপস্থাপনা বিলম্ব অনুকরণ করা যাক।

blockFor কলটিকে একটি requestAnimationFrame কলব্যাকে সরান যাতে ইভেন্ট লিসেনার ফিরে আসার পরে এটি চলে:

সম্পূর্ণ কোড দেখুন: presentation_delay.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
  requestAnimationFrame(() => {
    blockFor(1000);
  });
});

কি হয়?

১১. উপস্থাপনা বিলম্ব পরীক্ষার ফলাফল

সম্পূর্ণ কোড দেখুন: presentation_delay.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();
  requestAnimationFrame(() => {
    blockFor(1000);
  });
});

মিথস্ক্রিয়াটি এক সেকেন্ডের জন্য স্থায়ী হয়, তাহলে কী হল?

requestAnimationFrame পরবর্তী পেইন্টের আগে একটি কলব্যাকের অনুরোধ করে। যেহেতু INP ইন্টারঅ্যাকশন থেকে পরবর্তী পেইন্ট পর্যন্ত সময় পরিমাপ করে, তাই requestAnimationFrame এর blockFor(1000) পরবর্তী পেইন্টটিকে পুরো এক সেকেন্ডের জন্য ব্লক করে রাখে।

পারফর্মেন্স প্যানেলে এখনও এক সেকেন্ডের ইন্টারঅ্যাকশন

তবে, দুটি জিনিস লক্ষ্য করুন:

  • হোভারে, আপনি দেখতে পাবেন যে সমস্ত ইন্টারঅ্যাকশন সময় এখন "প্রেজেন্টেশন বিলম্ব" তে ব্যয় হচ্ছে কারণ ইভেন্ট লিসেনার ফিরে আসার পরে মূল-থ্রেড ব্লকিং ঘটছে।
  • মূল-থ্রেড কার্যকলাপের মূল আর ক্লিক ইভেন্ট নয়, বরং "অ্যানিমেশন ফ্রেম ফায়ারড"।

১২. মিথস্ক্রিয়া নির্ণয়

এই পরীক্ষা পৃষ্ঠায়, স্কোর, টাইমার এবং কাউন্টার UI সহ প্রতিক্রিয়াশীলতা অত্যন্ত দৃশ্যমান...কিন্তু গড় পৃষ্ঠা পরীক্ষা করার সময় এটি আরও সূক্ষ্ম।

যখন মিথস্ক্রিয়া দীর্ঘস্থায়ী হয়, তখন অপরাধী কে তা সবসময় স্পষ্ট হয় না। এটা কি:

  • ইনপুট বিলম্ব?
  • ইভেন্ট প্রক্রিয়াকরণের সময়কাল?
  • উপস্থাপনা বিলম্বিত?

আপনার পছন্দের যেকোনো পৃষ্ঠায়, প্রতিক্রিয়াশীলতা পরিমাপ করতে আপনি DevTools ব্যবহার করতে পারেন। অভ্যাসে পরিণত হতে, এই প্রবাহটি চেষ্টা করে দেখুন:

  1. আপনি সাধারণত যেভাবে ওয়েবে যান, সেভাবেই ওয়েবে নেভিগেট করুন।
  2. DevTools পারফরম্যান্স প্যানেলের লাইভ মেট্রিক্স ভিউতে ইন্টারঅ্যাকশন লগের দিকে নজর রাখুন।
  3. যদি আপনি একটি খারাপ পারফর্মিং ইন্টারঅ্যাকশন দেখতে পান, তাহলে এটি পুনরাবৃত্তি করার চেষ্টা করুন:
  • যদি আপনি এটি পুনরাবৃত্তি করতে না পারেন, তাহলে অন্তর্দৃষ্টি পেতে ইন্টারঅ্যাকশন লগ ব্যবহার করুন।
  • যদি আপনি এটি পুনরাবৃত্তি করতে পারেন, তাহলে পারফরম্যান্স প্যানেলে একটি ট্রেস রেকর্ড করুন।

সকল বিলম্ব

পৃষ্ঠাটিতে এই সমস্ত সমস্যাগুলির কিছুটা যোগ করার চেষ্টা করুন:

সম্পূর্ণ কোড দেখুন: all_the_things.html

setInterval(() => {
  blockFor(1000);
}, 3000);

button.addEventListener('click', () => {
  blockFor(1000);
  score.incrementAndUpdateUI();

  requestAnimationFrame(() => {
    blockFor(1000);
  });
});

তারপর সমস্যাগুলি নির্ণয়ের জন্য কনসোল এবং পারফরম্যান্স প্যানেল ব্যবহার করুন!

১৩. পরীক্ষা: অ্যাসিঙ্ক কাজ

যেহেতু আপনি ইন্টারঅ্যাকশনের ভেতরে নন-ভিজ্যুয়াল এফেক্ট শুরু করতে পারেন, যেমন নেটওয়ার্ক রিকোয়েস্ট করা, টাইমার শুরু করা, অথবা গ্লোবাল স্টেট আপডেট করা, তাহলে যখন পৃষ্ঠাটি শেষ পর্যন্ত আপডেট হয় তখন কী হয়?

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

এটি চেষ্টা করার জন্য, ক্লিক লিসেনার থেকে UI আপডেট করা চালিয়ে যান, কিন্তু টাইমআউট থেকে ব্লকিং কাজ চালান।

সম্পূর্ণ কোড দেখুন: timeout_100.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();

  setTimeout(() => {
    blockFor(1000);
  }, 100);
});

এখন কি হবে?

১৪. অ্যাসিঙ্ক কাজের পরীক্ষার ফলাফল

সম্পূর্ণ কোড দেখুন: timeout_100.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();

  setTimeout(() => {
    blockFor(1000);
  }, 100);
});

ট্রেসের পরে এক সেকেন্ড দীর্ঘ কাজের সাথে ২৭ মিলিসেকেন্ডের ইন্টারঅ্যাকশন ঘটছে

ইন্টারঅ্যাকশনটি এখন সংক্ষিপ্ত কারণ UI আপডেট করার পরপরই মূল থ্রেডটি উপলব্ধ থাকে। দীর্ঘ ব্লকিং টাস্কটি এখনও চলতে থাকে, এটি পেইন্ট করার কিছুক্ষণ পরেই চলে, তাই ব্যবহারকারী তাৎক্ষণিক UI প্রতিক্রিয়া পাবেন।

শিক্ষা: যদি তুমি এটি সরাতে না পারো, অন্তত এটি সরান!

পদ্ধতি

আমরা কি একটি নির্দিষ্ট ১০০ মিলিসেকেন্ডের setTimeout চেয়ে ভালো কিছু করতে পারি? আমরা সম্ভবত এখনও চাই কোডটি যত তাড়াতাড়ি সম্ভব রান হোক, অন্যথায় আমাদের এটি সরিয়ে ফেলা উচিত ছিল!

লক্ষ্য:

  • ইন্টারঅ্যাকশনটি incrementAndUpdateUI() চালাবে।
  • blockFor() যত তাড়াতাড়ি সম্ভব চলবে, কিন্তু পরবর্তী পেইন্টটি ব্লক করবে না।
  • এর ফলে "ম্যাজিক টাইমআউট" ছাড়াই অনুমানযোগ্য আচরণ তৈরি হয়।

এটি সম্পন্ন করার কিছু উপায় হল:

  • setTimeout(0)
  • Promise.then()
  • requestAnimationFrame
  • requestIdleCallback
  • scheduler.postTask()

"অনুরোধপোস্টঅ্যানিমেশনফ্রেম"

requestAnimationFrame এর নিজস্ব (যা পরবর্তী পেইন্টের আগে চালানোর চেষ্টা করবে এবং সাধারণত ধীর গতিতে ইন্টারঅ্যাকশন করবে) বিপরীতে, requestAnimationFrame + setTimeout এর জন্য একটি সহজ পলিফিল তৈরি করে, requestPostAnimationFrame পরবর্তী পেইন্টের পরে কলব্যাক চালায়।

সম্পূর্ণ কোড দেখুন: raf+task.html

function afterNextPaint(callback) {
  requestAnimationFrame(() => {
    setTimeout(callback, 0);
  });
}

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();

  afterNextPaint(() => {
    blockFor(1000);
  });
});

এরগনোমিক্সের জন্য, আপনি এটিকে একটি প্রতিশ্রুতিতেও মুড়ে রাখতে পারেন:

সম্পূর্ণ কোড দেখুন: raf+task2.html

async function nextPaint() {
  return new Promise(resolve => afterNextPaint(resolve));
}

button.addEventListener('click', async () => {
  score.incrementAndUpdateUI();

  await nextPaint();
  blockFor(1000);
});

১৫. একাধিক ইন্টারঅ্যাকশন (এবং রাগের ক্লিক)

দীর্ঘ ব্লকিং কাজ এদিক-ওদিক সরাতে সাহায্য করতে পারে, কিন্তু সেই দীর্ঘ কাজগুলি এখনও পৃষ্ঠাটিকে ব্লক করে, যা ভবিষ্যতের ইন্টারঅ্যাকশনের পাশাপাশি অন্যান্য অনেক পৃষ্ঠার অ্যানিমেশন এবং আপডেটগুলিকে প্রভাবিত করে।

পৃষ্ঠার অ্যাসিঙ্ক ব্লকিং কাজের সংস্করণটি আবার চেষ্টা করে দেখুন (অথবা যদি আপনি শেষ ধাপে কাজ স্থগিত করার জন্য নিজস্ব সংস্করণটি নিয়ে এসে থাকেন তবে আপনার নিজস্ব):

সম্পূর্ণ কোড দেখুন: timeout_100.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();

  setTimeout(() => {
    blockFor(1000);
  }, 100);
});

আপনি যদি দ্রুত একাধিকবার ক্লিক করেন তাহলে কী হবে?

পারফর্ম্যান্স ট্রেস

প্রতিটি ক্লিকের জন্য, এক সেকেন্ডের একটি টাস্ক সারিবদ্ধ থাকে, যা নিশ্চিত করে যে মূল থ্রেডটি যথেষ্ট সময়ের জন্য ব্লক করা থাকে।

মূল থ্রেডে একাধিক সেকেন্ড-লং টাস্ক, যার ফলে ইন্টারঅ্যাকশন 800 মিলিসেকেন্ডের মতো ধীর হয়ে যায়

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

কৌশল

আদর্শভাবে, আমরা দীর্ঘ কাজগুলি সম্পূর্ণরূপে বাদ দিতে চাই!

  • অপ্রয়োজনীয় কোড সম্পূর্ণরূপে মুছে ফেলুন—বিশেষ করে স্ক্রিপ্ট।
  • দীর্ঘ কাজ এড়াতে কোডটি অপ্টিমাইজ করুন।
  • নতুন মিথস্ক্রিয়া এলে পুরনো কাজ বন্ধ করে দিন।

১৬. কৌশল ১: ডিবাউন্স

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

  • ব্যয়বহুল কাজ শুরু করতে দেরি করতে setTimeout ব্যবহার করুন, একটি টাইমার সহ, সম্ভবত 500 থেকে 1000 মিলিসেকেন্ড।
  • যখন আপনি এটি করবেন তখন টাইমার আইডিটি সংরক্ষণ করুন।
  • যদি কোনও নতুন ইন্টারঅ্যাকশন আসে, তাহলে clearTimeout ব্যবহার করে পূর্ববর্তী টাইমারটি বাতিল করুন।

সম্পূর্ণ কোড দেখুন: debounce.html

let timer;
button.addEventListener('click', () => {
  score.incrementAndUpdateUI();

  if (timer) {
    clearTimeout(timer);
  }
  timer = setTimeout(() => {
    blockFor(1000);
  }, 1000);
});

পারফর্ম্যান্স ট্রেস

একাধিক মিথস্ক্রিয়া, কিন্তু সবগুলোর ফলে শুধুমাত্র একটি দীর্ঘ কাজ

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

১৭. কৌশল ২: দীর্ঘমেয়াদী কাজ ব্যাহত করা

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

আদর্শভাবে যদি আমাদের কাজের মাঝখানে কোনও মিথস্ক্রিয়া ঘটে, তাহলে আমরা আমাদের ব্যস্ত কাজ থামাতে চাই যাতে কোনও নতুন মিথস্ক্রিয়া তাৎক্ষণিকভাবে মোকাবেলা করা যায়। আমরা কীভাবে এটি করতে পারি?

কিছু API আছে যেমন isInputPending , কিন্তু সাধারণত লম্বা কাজগুলিকে খণ্ডে ভাগ করা ভালো

অনেক setTimeout

প্রথম প্রচেষ্টা: সহজ কিছু করুন।

সম্পূর্ণ কোড দেখুন: small_tasks.html

button.addEventListener('click', () => {
  score.incrementAndUpdateUI();

  requestAnimationFrame(() => {
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
    setTimeout(() => blockFor(100), 0);
  });
});

এটি ব্রাউজারকে প্রতিটি কাজ পৃথকভাবে নির্ধারণ করার অনুমতি দিয়ে কাজ করে এবং ইনপুটকে উচ্চতর অগ্রাধিকার দেওয়া যেতে পারে!

একাধিক ইন্টারঅ্যাকশন, কিন্তু সমস্ত নির্ধারিত কাজ অনেক ছোট ছোট কাজে বিভক্ত করা হয়েছে

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

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

তবে, এই কৌশলটি শক্তভাবে সংযুক্ত কোড ভাঙার ক্ষেত্রে তেমন ভালো কাজ করে না, যেমন একটি for লুপ যা শেয়ার্ড স্টেট ব্যবহার করে।

এখন yield() সহ

তবে, যেকোনো জাভাস্ক্রিপ্ট ফাংশনে সহজেই "ইয়েল্ড পয়েন্ট" যোগ করার জন্য আমরা আধুনিক async এবং await ব্যবহার করতে পারি।

উদাহরণস্বরূপ:

সম্পূর্ণ কোড দেখুন: yieldy.html

// Polyfill for scheduler.yield()
async function schedulerDotYield() {
  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
}

async function blockInPiecesYieldy(ms) {
  const ms_per_part = 10;
  const parts = ms / ms_per_part;
  for (let i = 0; i < parts; i++) {
    await schedulerDotYield();

    blockFor(ms_per_part);
  }
}

button.addEventListener('click', async () => {
  score.incrementAndUpdateUI();
  await blockInPiecesYieldy(1000);
});

আগের মতোই, অনেক কাজ করার পর মূল থ্রেডটি বেরিয়ে আসে এবং ব্রাউজার যেকোনো ইনকামিং ইন্টারঅ্যাকশনের প্রতিক্রিয়া জানাতে সক্ষম হয়, কিন্তু এখন যা প্রয়োজন তা হল আলাদা setTimeout এর পরিবর্তে একটি await schedulerDotYield() , যা এটিকে for লুপের মাঝখানেও ব্যবহারের জন্য যথেষ্ট এর্গোনমিক করে তোলে।

এখন AbortContoller() এর সাথে

এটা কাজ করেছে, কিন্তু প্রতিটি মিথস্ক্রিয়া আরও কাজের সময়সূচী তৈরি করে, এমনকি যদি নতুন মিথস্ক্রিয়া আসে এবং প্রয়োজনীয় কাজটি পরিবর্তন করে থাকে।

ডিবাউন্সিং কৌশলের মাধ্যমে, আমরা প্রতিটি নতুন ইন্টারঅ্যাকশনের সাথে পূর্ববর্তী টাইমআউট বাতিল করেছি। আমরা কি এখানেও একই রকম কিছু করতে পারি? এটি করার একটি উপায় হল AbortController() ব্যবহার করা:

সম্পূর্ণ কোড দেখুন: aborty.html

// Polyfill for scheduler.yield()
async function schedulerDotYield() {
  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
}

async function blockInPiecesYieldyAborty(ms, signal) {
  const parts = ms / 10;
  for (let i = 0; i < parts; i++) {
    // If AbortController has been asked to stop, abandon the current loop.
    if (signal.aborted) return;

    await schedulerDotYield();

    blockFor(10);
  }
}

let abortController = new AbortController();

button.addEventListener('click', async () => {
  score.incrementAndUpdateUI();

  abortController.abort();
  abortController = new AbortController();

  await blockInPiecesYieldyAborty(1000, abortController.signal);
});

যখন একটি ক্লিক আসে, তখন এটি blockInPiecesYieldyAborty for লুপ চালু করে যা যা করা প্রয়োজন তা করে এবং পর্যায়ক্রমে মূল থ্রেডটি প্রদান করে যাতে ব্রাউজারটি নতুন ইন্টারঅ্যাকশনের প্রতি প্রতিক্রিয়াশীল থাকে।

যখন দ্বিতীয়বার ক্লিক করা হয়, তখন AbortController দিয়ে প্রথম লুপটি বাতিল হিসেবে চিহ্নিত করা হয় এবং একটি নতুন blockInPiecesYieldyAborty লুপ শুরু হয়—পরের বার যখন প্রথম লুপটি আবার চালানোর জন্য নির্ধারিত হয়, তখন এটি লক্ষ্য করে যে signal.aborted এখন true এবং তাৎক্ষণিকভাবে আর কোনও কাজ না করেই ফিরে আসে।

মূল থ্রেডের কাজ এখন অনেক ছোট ছোট টুকরোতে বিভক্ত, মিথস্ক্রিয়া সংক্ষিপ্ত, এবং কাজ কেবল ততক্ষণ স্থায়ী হয় যতক্ষণ এটি প্রয়োজন

১৮. উপসংহার

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

মনে রাখবেন

  • INP সকল মিথস্ক্রিয়া পরিমাপ করে।
  • প্রতিটি মিথস্ক্রিয়া ইনপুট থেকে পরবর্তী পেইন্ট পর্যন্ত পরিমাপ করা হয়—ব্যবহারকারী যেভাবে প্রতিক্রিয়াশীলতা দেখেন
  • ইনপুট বিলম্ব, ইভেন্ট প্রক্রিয়াকরণের সময়কাল এবং উপস্থাপনার বিলম্ব - এই সবকিছুই ইন্টারঅ্যাকশনের প্রতিক্রিয়াশীলতাকে প্রভাবিত করে।
  • DevTools দিয়ে আপনি সহজেই INP এবং ইন্টারঅ্যাকশন ব্রেকডাউন পরিমাপ করতে পারবেন!

কৌশল

  • আপনার পৃষ্ঠাগুলিতে দীর্ঘমেয়াদী কোড (দীর্ঘ কাজ) রাখবেন না।
  • পরবর্তী পেইন্টের পর পর্যন্ত ইভেন্ট লিসেনারের বাইরে অপ্রয়োজনীয় কোড সরান।
  • নিশ্চিত করুন যে রেন্ডারিং আপডেটটি নিজেই ব্রাউজারের জন্য দক্ষ।

আরও জানুন