Interaction to Next Paint (INP) পরিমাপ করা

১. ভূমিকা

web-vitals লাইব্রেরি ব্যবহার করে কীভাবে Interaction to Next Paint (INP) পরিমাপ করতে হয় তা শেখার জন্য এটি একটি ইন্ট্যার‍্যাক্টিভ কোডল্যাব।

পূর্বশর্ত

আপনি কী শিখবেন

  • আপনার পৃষ্ঠায় কীভাবে web-vitals লাইব্রেরি যোগ করবেন এবং এর অ্যাট্রিবিউশন ডেটা ব্যবহার করবেন।
  • কোথায় ও কীভাবে INP উন্নত করা শুরু করতে হবে তা ডায়াগনসিস করতে অ্যাট্রিবিউশন ডেটা ব্যবহার করুন।

আপনার কী কী প্রয়োজন হবে

  • GitHub থেকে কোড ক্লোন করতে এবং npm কমান্ড রান করতে পারে এমন কম্পিউটার।
  • টেক্সট এডিটর।
  • সব ইন্টার‍্যাকশন পরিমাপ করার জন্য Chrome-এর সাম্প্রতিক ভার্সন।

২. সেট-আপ করা

কোড পাওয়া ও চালানো

কোডটি web-vitals-codelabs রিপোজিটরিতে পাওয়া যাবে।

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

পৃষ্ঠাটি ব্যবহার করে দেখুন

এই কোডল্যাব INP-এর সম্ভাব্য সমস্যা এক্সপ্লোর করতে Gastropodicon (একটি জনপ্রিয় শামুক অ্যানাটমি রেফারেন্স সাইট) ব্যবহার করে।

Gastropodicon ডেমো পৃষ্ঠার স্ক্রিনশট

কোন কোন ইন্টার‍্যাকশন ধীরে হচ্ছে তা বুঝতে পৃষ্ঠার সাথে ইন্টার‍্যাক্ট করে দেখুন।

৩. Chrome DevTools-এ অভ্যস্ত হওয়া

আরও টুল > ডেভেলপার টুল মেনু থেকে DevTools খুলুন, পৃষ্ঠায় ডানদিকের বোতামে ক্লিক করে পরীক্ষা করুন বিকল্প বেছে নিন অথবা কীবোর্ড শর্টকাট ব্যবহার করুন।

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

  • INP সংক্রান্ত সমস্যা বেশিরভাগ ক্ষেত্রেই মোবাইল ডিভাইসে হয়, তাই মোবাইল ডিসপ্লে এমুলেশনে পরিবর্তন করুন।
  • আপনি ডেস্কটপ বা ল্যাপটপে পরীক্ষা করলে, পারফর্ম্যান্স সম্ভবত আসল মোবাইল ডিভাইসের চেয়ে অনেক ভাল হবে। পারফর্ম্যান্সের আরও বাস্তবসম্মত চিত্র পেতে, পারফর্ম্যান্স প্যানেলের উপরে ডানদিকে গিয়ার আইকনে ক্লিক করুন, তারপর CPU ৪x স্লো ডাউন বিকল্প বেছে নিন।

অ্যাপের সাথে DevTools পারফর্ম্যান্স প্যানেলের স্ক্রিনশট, যেখানে ৪x সিপিইউ স্লোডাউন বেছে নেওয়া হয়েছে

৪. web-vitals ইনস্টল করা হচ্ছে

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

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

এই কোডল্যাব npm থেকে ইনস্টল করবে এবং কোনও নির্দিষ্ট বিল্ড প্রসেসে না গিয়ে সরাসরি স্ক্রিপ্ট লোড করবে।

web-vitals-এর দুটি ভার্সন আপনি ব্যবহার করতে পারবেন:

  • আপনি যদি কোনও পৃষ্ঠা লোড করার সময় Core Web Vitals-এর মেট্রিক ভ্যালু ট্র্যাক করতে চান, তাহলে "স্ট্যান্ডার্ড" বিল্ড ব্যবহার করা উচিত।
  • "অ্যাট্রিবিউশন" বিল্ড প্রতিটি মেট্রিকের সাথে অতিরিক্ত ডিবাগ তথ্য যোগ করে, যাতে কোনও মেট্রিকের মান কেন এমন হল তা বোঝা যায়।

এই কোডল্যাবে INP পরিমাপ করার জন্য, আমরা অ্যাট্রিবিউশন বিল্ড চাই।

npm install -D web-vitals চালিয়ে প্রোজেক্টের devDependencies-এ web-vitals যোগ করুন

পৃষ্ঠায় web-vitals যোগ করুন:

index.html-এর নিচে স্ক্রিপ্টের অ্যাট্রিবিউশন ভার্সন যোগ করুন এবং কনসোলে ফলাফল লগ করুন:

<script type="module">
  import {onINP} from './node_modules/web-vitals/dist/web-vitals.attribution.js';

  onINP(console.log);
</script>

এটি ব্যবহার করে দেখুন

কনসোল খোলা রেখে আবার পৃষ্ঠার সাথে ইন্টার‍্যাক্ট করার চেষ্টা করুন। আপনি পৃষ্ঠার চারপাশে ক্লিক করলেও, কিছুই লগ করা হয় না!

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

web-vitals আরও বিস্তারিত রিপোর্টিংয়ের জন্য reportAllChanges বিকল্প প্রদান করে। চালু করা হলে, প্রতিটি ইন্টার‍্যাকশন রিপোর্ট করা হয় না, তবে যখনই কোনও ইন্টার‍্যাকশন আগের ইন্টার‍্যাকশনের চেয়ে ধীরে হয়, তখনই তা রিপোর্ট করা হয়।

স্ক্রিপ্টে বিকল্প যোগ করে আবার পৃষ্ঠার সাথে ইন্টার‍্যাক্ট করে দেখুন:

<script type="module">
  import {onINP} from './node_modules/web-vitals/dist/web-vitals.attribution.js';

  onINP(console.log, {reportAllChanges: true});
</script>

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

DevTools কনসোলের একটি স্ক্রিনশট যেখানে INP মেসেজ সফলভাবে প্রিন্ট করা হয়েছে

৫. অ্যাট্রিবিউশনে কী থাকে?

আসুন, পৃষ্ঠার সাথে বেশিরভাগ ব্যবহারকারীর প্রথম ইন্টার‍্যাকশন, অর্থাৎ কুকি সম্মতি ডায়ালগ থেকে শুরু করা যাক।

অনেক পৃষ্ঠায় এমন স্ক্রিপ্ট থাকে যেগুলির জন্য ব্যবহারকারী কুকি গ্রহণ করলে, কুকি সিঙ্ক্রোনাসভাবে ট্রিগার করতে হয়, এর ফলে ক্লিক করার পরে ইন্টার‍্যাকশন ধীরে ধীরে হয়। এখানে এটাই হয়।

(ডেমো) কুকি গ্রহণ করতে হ্যাঁ বিকল্পে ক্লিক করুন এবং DevTools কনসোলে এখন লগ করা INP ডেটা দেখুন।

DevTools কনসোলে লগ করা INP ডেটা অবজেক্ট

এই টপ-লেভেল তথ্য স্ট্যান্ডার্ড ও অ্যাট্রিবিউশন ওয়েব-ভাইটাল বিল্ড, দুটিতেই উপলভ্য:

{
  name: 'INP',
  value: 344,
  rating: 'needs-improvement',
  entries: [...],
  id: 'v4-1715732159298-8028729544485',
  navigationType: 'reload',
  attribution: {...},
}

ব্যবহারকারী ক্লিক করার পর থেকে নেক্সট পেইন্ট পর্যন্ত সময় লেগেছে ৩৪৪ মিলিসেকেন্ড—এটি "উন্নত করা প্রয়োজন" INP। entries অ্যারেতে এই ইন্টার‍্যাকশনের সাথে যুক্ত সব PerformanceEntry ভ্যালু আছে—এই ক্ষেত্রে, শুধুমাত্র একটি ক্লিক ইভেন্ট।

তবে, এই সময় কী ঘটছে তা খুঁজে বের করতে, আমরা সবচেয়ে বেশি আগ্রহী attribution প্রপার্টিতে। অ্যাট্রিবিউশন ডেটা তৈরি করতে, web-vitals দেখে যে কোন লং অ্যানিমেশন ফ্রেম (LoAF) ক্লিক ইভেন্টের সাথে ওভারল্যাপ করছে। LoAF তখন সেই ফ্রেমের মধ্যে কীভাবে সময় ব্যয় করা হয়েছিল, সেই সম্পর্কে বিস্তারিত ডেটা প্রদান করতে পারে। এর মধ্যে স্ক্রিপ্ট থেকে শুরু করে requestAnimationFrame কলব্যাক, স্টাইল এবং লেআউটে ব্যয় করা সময় অন্তর্ভুক্ত।

আরও তথ্য দেখতে attribution প্রপার্টি বড় করুন। ডেটা অনেক বেশি সমৃদ্ধ।

attribution: {
  interactionTargetElement: Element,
  interactionTarget: '#confirm',
  interactionType: 'pointer',

  inputDelay: 27,
  processingDuration: 295.6,
  presentationDelay: 21.4,

  processedEventEntries: [...],
  longAnimationFrameEntries: [...],
}

প্রথমত, কী কী ইন্টার‍্যাক্ট করা হয়েছে সেই সম্পর্কিত তথ্য:

  • interactionTargetElement: ইন্টার‍্যাক্ট করা এলিমেন্টের লাইভ রেফারেন্স (যদি এলিমেন্টটি DOM থেকে সরানো না হয়ে থাকে)।
  • interactionTarget: পৃষ্ঠার মধ্যে এলিমেন্ট খুঁজে পাওয়ার জন্য একটি বাছাইকারী।

এরপরে, সময়কে হাই-লেভেল পদ্ধতিতে ভাগ করা হয়েছে:

  • inputDelay: ব্যবহারকারী ইন্টার‍্যাকশন শুরু করার (যেমন, মাউসে ক্লিক করা) সময় থেকে সেই ইন্টার‍্যাকশনের জন্য ইভেন্ট লিসনার রান করা শুরু করার মধ্যবর্তী সময়। এই ক্ষেত্রে, CPU থ্রটলিং চালু থাকা সত্ত্বেও ইনপুট ডিলে মাত্র ২৭ মিলিসেকেন্ড ছিল।
  • processingDuration: ইভেন্ট লিসনার সম্পূর্ণ রান হতে যে সময় লাগে। প্রায়ই, কোনও পৃষ্ঠায় একটি ইভেন্টের জন্য একাধিক লিসনার থাকে (যেমন, pointerdown, pointerup ও click)। এগুলি একই অ্যানিমেশন ফ্রেমে রান করলে, এই সময়ের মধ্যে এগুলিকে একত্রিত করা হবে। এই ক্ষেত্রে, প্রসেসিংয়ের সময় লাগে ২৯৫.৬ মিলিসেকেন্ড—এটিই হল INP-এর বেশিরভাগ সময়।
  • presentationDelay: ইভেন্ট লিসনার সম্পূর্ণ হওয়ার সময় থেকে ব্রাউজার পরবর্তী ফ্রেম পেন্টিং শেষ করার সময় পর্যন্ত। এই ক্ষেত্রে, ২১.৪ মিলিসেকেন্ড।

কী অপ্টিমাইজ করতে হবে তা নির্ণয় করার জন্য এই INP ফেজগুলি গুরুত্বপূর্ণ সিগন্যাল হতে পারে। INP অপ্টিমাইজ করার গাইড থেকে এই বিষয়ে আরও তথ্য পাবেন।

একটু গভীরে গিয়ে দেখলে, টপ-লেভেল INP entries অ্যারেতে একটি ইভেন্টের বিপরীতে processedEventEntries-এ পাঁচটি ইভেন্ট রয়েছে। দু'টির মধ্যে পার্থক্য কী?

processedEventEntries: [
  {
    name: 'mouseover',
    entryType: 'event',
    startTime: 1801.6,
    duration: 344,
    processingStart: 1825.3,
    processingEnd: 1825.3,
    cancelable: true
  },
  {
    name: 'mousedown',
    entryType: 'event',
    startTime: 1801.6,
    duration: 344,
    processingStart: 1825.3,
    processingEnd: 1825.3,
    cancelable: true
  },
  {name: 'mousedown', ...},
  {name: 'mouseup', ...},
  {name: 'click', ...},
],

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

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

longAnimationFrameEntries

LoAF এন্ট্রি বড় করা হচ্ছে:

longAnimationFrameEntries: [{
  name: 'long-animation-frame',
  startTime: 1823,
  duration: 319,

  renderStart: 2139.5,
  styleAndLayoutStart: 2139.7,
  firstUIEventTimestamp: 1801.6,
  blockingDuration: 268,

  scripts: [{...}]
}],

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

scripts: [{
  name: 'script',
  invoker: 'BUTTON#confirm.onclick',
  invokerType: 'event-listener',

  startTime: 1828.6,
  executionStart: 1828.6,
  duration: 294,

  sourceURL: 'http://localhost:8080/third-party/cmp.js',
  sourceFunctionName: '',
  sourceCharPosition: 1144
}]

এই ক্ষেত্রে, আমরা বলতে পারি যে বেশিরভাগ সময় একটি event-listener-এ ব্যয় করা হয়েছে, যা BUTTON#confirm.onclick-এ ইনভোক করা হয়েছে। এমনকি, আমরা স্ক্রিপ্টের সোর্স URL এবং ফাংশনটি যেখানে ডিফাইন করা হয়েছে সেই অক্ষর পজিশনও দেখতে পাই!

টেক-অ্যাওয়ে

এই অ্যাট্রিবিউশন ডেটা থেকে এই কেস সম্পর্কে কী নির্ধারণ করা যেতে পারে?

  • button#confirm এলিমেন্টে ক্লিক করার মাধ্যমে ইন্টার‍্যাকশন ট্রিগার করা হয়েছে (attribution.interactionTarget থেকে এবং স্ক্রিপ্ট অ্যাট্রিবিউশন এন্ট্রিতে invoker প্রপার্টি)।
  • বেশিরভাগ সময় ইভেন্ট লিসনার (attribution.processingDuration থেকে মোট মেট্রিক value-এর তুলনায়) এক্সিকিউট করতে খরচ হয়েছে।
  • ধীর ইভেন্ট লিসনার কোড third-party/cmp.js-এ (scripts.sourceURL থেকে) সংজ্ঞায়িত ক্লিক লিসনার থেকে শুরু হয়।

কোথায় অপ্টিমাইজ করতে হবে তা জানার জন্য এই ডেটাই যথেষ্ট!

৬. একাধিক ইভেন্ট লিসনার

পৃষ্ঠা রিফ্রেশ করুন যাতে DevTools কনসোল পরিষ্কার থাকে এবং কুকি সম্মতি সংক্রান্ত ইন্টার‍্যাকশন আর সবচেয়ে দীর্ঘ ইন্টার‍্যাকশন না হয়।

সার্চ বক্সে টাইপ করা শুরু করুন। অ্যাট্রিবিউশন ডেটা কী দেখায়? কী হচ্ছে বলে তোমার মনে হয়?

অ্যাট্রিবিউশন ডেটা

প্রথমে, ডেমো পরীক্ষা করার একটি উদাহরণ সম্পর্কে একটি উচ্চ-স্তরের স্ক্যান:

{
  name: 'INP',
  value: 1072,
  rating: 'poor',
  attribution: {
    interactionTargetElement: Element,
    interactionTarget: '#search-terms',
    interactionType: 'keyboard',

    inputDelay: 3.3,
    processingDuration: 1060.6,
    presentationDelay: 8.1,

    processedEventEntries: [...],
    longAnimationFrameEntries: [...],
  }
}

input#search-terms এলিমেন্টের সাথে কীবোর্ড ইন্টার‍্যাকশনের ফলে এটি একটি খারাপ INP ভ্যালু (সিপিইউ থ্রটলিং চালু করা আছে)। বেশিরভাগ সময়—মোট ১০৭২ মিলিসেকেন্ডের মধ্যে ১০৬১ মিলিসেকেন্ড INP—প্রসেসিংয়ের সময় লেগেছে।

তবে, scripts এন্ট্রিগুলি আরও বেশি আকর্ষণীয়।

লেআউট থ্র্যাশিং

scripts অ্যারের প্রথম এন্ট্রি থেকে আমরা কিছু গুরুত্বপূর্ণ প্রসঙ্গ পাই:

scripts: [{
  name: 'script',
  invoker: 'BUTTON#confirm.onclick',
  invokerType: 'event-listener',

  startTime: 4875.6,
  executionStart: 4875.6,
  duration: 497,
  forcedStyleAndLayoutDuration: 388,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: 'handleSearch',
  sourceCharPosition: 940
},
...]

প্রসেসিংয়ের বেশিরভাগ সময় এই স্ক্রিপ্ট এক্সিকিউশনের সময় লাগে, এটি একটি input লিসনার (ইনভকার হল INPUT#search-terms.oninput)। ফাংশনের নাম দেওয়া আছে (handleSearch), যেমন index.js সোর্স ফাইলের মধ্যে অক্ষর পজিশন।

তবে, একটি নতুন প্রপার্টি আছে: forcedStyleAndLayoutDuration। এই স্ক্রিপ্ট ইনভোকেশনের মধ্যে এটি হল সেই সময় যেখানে ব্রাউজারকে পৃষ্ঠাটি আবার লেআউট করতে বাধ্য করা হয়েছে। অন্যভাবে বলতে গেলে, এই ইভেন্ট লিসনারকে এক্সিকিউট করার জন্য যে সময় ব্যয় করা হয়েছে—৪৯৭ মিলিসেকেন্ডের মধ্যে ৩৮৮ মিলিসেকেন্ড—তার ৭৮% আসলে লেআউট থ্র্যাশিংয়ে ব্যয় করা হয়েছে।

এটি সমাধান করার জন্য সবচেয়ে বেশি অগ্রাধিকার দেওয়া উচিত।

বারবার শুনছেন এমন শ্রোতা

আলাদাভাবে, পরবর্তী দুটি স্ক্রিপ্ট এন্ট্রি সম্পর্কে বিশেষ উল্লেখযোগ্য কিছু নেই:

scripts: [...,
{
  name: 'script',
  invoker: '#document.onkeyup',
  invokerType: 'event-listener',

  startTime: 5375.3,
  executionStart: 5375.3,
  duration: 124,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: '',
  sourceCharPosition: 1526,
},
{
  name: 'script',
  invoker: '#document.onkeyup',
  invokerType: 'event-listener',

  startTime: 5673.9,
  executionStart: 5673.9,
  duration: 95,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: '',
  sourceCharPosition: 1526
}]

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

যা অদ্ভুত তা হল, দুটিই একই সোর্স ফাইল ও অক্ষর পজিশন থেকে নেওয়া হয়েছে।

ব্রাউজারটি একটি অ্যানিমেশন ফ্রেমে একাধিক কীপ্রেস প্রসেস করে, যার ফলে কোনও কিছু আঁকার আগেই এই ইভেন্ট লিসনার দুবার রান করে!

এই প্রভাবটি আরও বাড়তে পারে, যেখানে ইভেন্ট লিসনার সম্পূর্ণ করতে যত বেশি সময় নেয়, তত বেশি অতিরিক্ত ইনপুট ইভেন্ট আসতে পারে, যার ফলে ইন্টার‍্যাকশন আরও বেশি সময় ধরে ধীরে ধীরে চলতে থাকে।

যেহেতু এটি একটি সার্চ/অটোকমপ্লিট ইন্টার‍্যাকশন, তাই ইনপুট ডিবাউন্স করা একটি ভাল কৌশল হবে যাতে সর্বাধিক, প্রতি ফ্রেমে একটি কীপ্রেস প্রসেস করা হয়।

৭. ইনপুট দিতে দেরি

ইনপুট বিলম্বের সাধারণ কারণ হল—ব্যবহারকারী ইন্টার‍্যাক্ট করার সময় থেকে ইভেন্ট লিসনার ইন্টার‍্যাকশন প্রসেস করা শুরু করার সময় পর্যন্ত—কারণ মূল থ্রেড ব্যস্ত থাকে। এর একাধিক কারণ থাকতে পারে:

  • পেজ লোড হচ্ছে এবং মূল থ্রেড DOM সেট-আপ করা, পেজ লে-আউট ও স্টাইল করা এবং স্ক্রিপ্ট মূল্যায়ন ও চালানোর প্রাথমিক কাজ করতে ব্যস্ত।
  • পৃষ্ঠাটি সাধারণত ব্যস্ত থাকে—যেমন, গণনা, স্ক্রিপ্ট-ভিত্তিক অ্যানিমেশন বা বিজ্ঞাপন চালানো।
  • আগের ইন্টার‍্যাকশন প্রসেস করতে এত বেশি সময় লাগে যে তা ভবিষ্যতের ইন্টার‍্যাকশনকে বিলম্বিত করে, যা শেষ উদাহরণে দেখা গেছে।

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

  • অ্যানিমেশন শুরু করতে, শামুক লোগোতে ক্লিক করুন।
  • স্নেলটি বাউন্সের সবচেয়ে নিচে পৌঁছালে জাভাস্ক্রিপ্ট টাস্ক ট্রিগার হয়। যতটা সম্ভব বাউন্সের নিচের দিকে পৃষ্ঠার সাথে ইন্টার‍্যাক্ট করার চেষ্টা করুন এবং দেখুন যে আপনি কতটা বেশি INP ট্রিগার করতে পারেন।

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

অনেক পৃষ্ঠায়, ভারী মূল থ্রেড এত ভাল আচরণ করবে না, কিন্তু INP অ্যাট্রিবিউশন ডেটাতে এটি কীভাবে শনাক্ত করা যায় তা দেখার জন্য এটি একটি ভাল ডেমোনস্ট্রেশন।

স্নেল বাউন্স চলাকালীন শুধুমাত্র সার্চ বক্সের উপর ফোকাস করার ফলে অ্যাট্রিবিউশনের একটি উদাহরণ এখানে দেওয়া হল:

{
  name: 'INP',
  value: 728,
  rating: 'poor',

  attribution: {
    interactionTargetElement: Element,
    interactionTarget: '#search-terms',
    interactionType: 'pointer',

    inputDelay: 702.3,
    processingDuration: 4.9,
    presentationDelay: 20.8,

    longAnimationFrameEntries: [{
      name: 'long-animation-frame',
      startTime: 2064.8,
      duration: 790,

      renderStart: 2065,
      styleAndLayoutStart: 2854.2,
      firstUIEventTimestamp: 0,
      blockingDuration: 740,

      scripts: [{...}]
    }]
  }
}

যেমনটি অনুমান করা হয়েছিল, ইভেন্ট লিসনার দ্রুত এক্সিকিউট হয়েছে—৪.৯ মিলিসেকেন্ডের প্রসেসিং সময় দেখায় এবং বেশিরভাগ খারাপ ইন্টার‍্যাকশন ইনপুট ডিলেতে ব্যয় করা হয়েছে, যা মোট ৭২৮ মিলিসেকেন্ডের মধ্যে ৭০২.৩ মিলিসেকেন্ড সময় নিয়েছে।

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

LoAF স্ক্রিপ্ট এন্ট্রি এখানে দেওয়া হল:

scripts: [{
  name: 'script',
  invoker: 'SPAN.onanimationiteration',
  invokerType: 'event-listener',

  startTime: 2065,
  executionStart: 2065,
  duration: 788,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: 'cryptodaphneCoinHandler',
  sourceCharPosition: 1831
}]

যদিও এই ফাংশনের সাথে ইন্টার‍্যাকশনের কোনও সম্পর্ক নেই, তবুও এটি অ্যানিমেশন ফ্রেমের গতি কমিয়ে দেয় এবং তাই ইন্টার‍্যাকশন ইভেন্টের সাথে যুক্ত LoAF ডেটাতে এটি অন্তর্ভুক্ত করা হয়।

এর থেকে আমরা দেখতে পাই যে ইন্টার‍্যাকশন প্রসেসিংয়ে দেরি করা ফাংশনটি কীভাবে ট্রিগার করা হয়েছে (animationiteration লিসনারের মাধ্যমে), ঠিক কোন ফাংশনটি এর জন্য দায়ী এবং আমাদের সোর্স ফাইলে এটি কোথায় অবস্থিত।

৮. প্রেজেন্টেশন বিলম্বিত হওয়া: যখন কোনও আপডেট পেইন্ট করা যায় না

প্রেজেন্টেশন ডিলে পরিমাপ করে যে ইভেন্ট লিসেনার কখন রান করা শেষ করেছে থেকে শুরু করে কখন ব্রাউজার স্ক্রিনে নতুন ফ্রেম পেইন্ট করতে পেরেছে, ব্যবহারকারীকে দৃশ্যমান ফিডব্যাক দেখানো পর্যন্ত সময়।

আবার INP ভ্যালু রিসেট করতে পৃষ্ঠা রিফ্রেশ করুন, তারপর হ্যামবার্গার মেনু খুলুন। এটি খোলার সময় একটি নির্দিষ্ট সমস্যা হয়।

এটি দেখতে কেমন?

{
  name: 'INP',
  value: 376,
  rating: 'needs-improvement',
  delta: 352,

  attribution: {
    interactionTarget: '#sidenav-button>svg',
    interactionType: 'pointer',

    inputDelay: 12.8,
    processingDuration: 14.7,
    presentationDelay: 348.5,

    longAnimationFrameEntries: [{
      name: 'long-animation-frame',
      startTime: 651,
      duration: 365,

      renderStart: 673.2,
      styleAndLayoutStart: 1004.3,
      firstUIEventTimestamp: 138.6,
      blockingDuration: 315,

      scripts: [{...}]
    }]
  }
}

এইবার প্রেজেন্টেশন বিলম্ব বেশিরভাগ ধীর ইন্টার‍্যাকশনের কারণ। এর অর্থ হল, ইভেন্ট লিসেনার সম্পূর্ণ হওয়ার পরে যা কিছু মূল থ্রেডকে ব্লক করছে তা ঘটে।

scripts: [{
  entryType: 'script',
  invoker: 'FrameRequestCallback',
  invokerType: 'user-callback',

  startTime: 673.8,
  executionStart: 673.8,
  duration: 330,

  sourceURL: 'http://localhost:8080/js/side-nav.js',
  sourceFunctionName: '',
  sourceCharPosition: 1193,
}]

scripts অ্যারের মধ্যে থাকা একটি এন্ট্রি থেকে আমরা দেখতে পাচ্ছি যে FrameRequestCallback থেকে user-callback-এ সময় ব্যয় করা হয়েছে। এইবার প্রেজেন্টেশন দেরির কারণ হল requestAnimationFrame কলব্যাক।

৯. উপসংহার

ফিল্ড ডেটা একত্রিত করা

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

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

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

একইভাবে, scripts এন্ট্রিতে sourceURL পাথে ফাইল-ভিত্তিক হ্যাশ থাকতে পারে যা সেগুলিকে একত্রিত করা কঠিন করে তোলে, তবে ডেটা ফেরত পাঠানোর আগে আপনার পরিচিত বিল্ড প্রসেসের উপর ভিত্তি করে হ্যাশ সরিয়ে দিতে পারেন।

এই ধরনের জটিল ডেটা নিয়ে কাজ করার কোনও সহজ উপায় নেই, তবে এর একটি সাবসেট ব্যবহার করাও ডিবাগিং প্রক্রিয়ার জন্য কোনও অ্যাট্রিবিউশন ডেটা না থাকার চেয়ে অনেক বেশি মূল্যবান।

সব জায়গায় অ্যাট্রিবিউশন!

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

আপনি এখন যেকোনও সাইটে INP অ্যাট্রিবিউশন ডেটা ব্যবহার করার জন্য প্রস্তুত!

এমনকি কোনও পৃষ্ঠা এডিট করার অ্যাক্সেস না থাকলেও, আপনি কী খুঁজে পান তা দেখতে DevTools কনসোলে নিম্নলিখিত স্নিপেট রান করিয়ে এই কোডল্যাব থেকে প্রসেসটি আবার তৈরি করতে পারবেন:

const script = document.createElement('script');
script.src = 'https://unpkg.com/web-vitals@4/dist/web-vitals.attribution.iife.js';
script.onload = function () {
  webVitals.onINP(console.log, {reportAllChanges: true});
};
document.head.appendChild(script);

আরও জানুন