দীর্ঘ অ্যানিমেশন ফ্রেম API

লং অ্যানিমেশন ফ্রেম এপিআই (LoAF-উচ্চারিত Lo-Af) হল লং টাস্ক এপিআই- এর একটি আপডেট যাতে স্লো ইউজার ইন্টারফেস (UI) আপডেটগুলি আরও ভালভাবে বোঝা যায়। এটি ধীরগতির অ্যানিমেশন ফ্রেমগুলি সনাক্ত করতে কার্যকর হতে পারে যা ইন্টারঅ্যাকশন টু নেক্সট পেইন্ট (আইএনপি) কোর ওয়েব ভাইটাল মেট্রিককে প্রভাবিত করতে পারে যা প্রতিক্রিয়াশীলতা পরিমাপ করে, বা অন্যান্য UI জ্যাঙ্ক সনাক্ত করতে যা মসৃণতাকে প্রভাবিত করে।

API এর স্থিতি

ব্রাউজার সমর্থন

  • ক্রোম: 123।
  • প্রান্ত: 123।
  • ফায়ারফক্স: সমর্থিত নয়।
  • সাফারি: সমর্থিত নয়।

উৎস

Chrome 116 থেকে Chrome 122-এ একটি অরিজিন ট্রায়াল অনুসরণ করে, LoAF API Chrome 123 থেকে পাঠানো হয়েছে।

পটভূমি: লং টাস্ক API

ব্রাউজার সমর্থন

  • ক্রোম: 58।
  • প্রান্ত: 79।
  • ফায়ারফক্স: সমর্থিত নয়।
  • সাফারি: সমর্থিত নয়।

উৎস

লং অ্যানিমেশন ফ্রেম এপিআই হল লং টাস্ক এপিআই এর একটি বিকল্প যা কিছু সময়ের জন্য ক্রোমে উপলব্ধ (ক্রোম 58 থেকে)। এর নাম অনুসারে, লং টাস্ক এপিআই আপনাকে দীর্ঘ কাজগুলির জন্য নিরীক্ষণ করতে দেয়, যেগুলি 50 মিলিসেকেন্ড বা তার বেশি সময়ের জন্য মূল থ্রেড দখল করে। একটি PeformanceObserver এর সাহায্যে PerformanceLongTaskTiming ইন্টারফেস ব্যবহার করে দীর্ঘ কাজগুলি পর্যবেক্ষণ করা যেতে পারে:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'longtask', buffered: true });

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

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

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

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

লং টাস্ক এপিআই এর ত্রুটি

একটি পারফরম্যান্স পর্যবেক্ষক ব্যবহার করে ক্ষেত্রের দীর্ঘ কাজগুলি পরিমাপ করা শুধুমাত্র কিছুটা কার্যকর। বাস্তবে, এটি এত বেশি তথ্য দেয় না যে একটি দীর্ঘ কাজ ঘটেছে, এবং কত সময় লেগেছে।

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

{
  "name": "unknown",
  "entryType": "longtask",
  "startTime": 31.799999997019768,
  "duration": 136,
  "attribution": [
    {
      "name": "unknown",
      "entryType": "taskattribution",
      "startTime": 0,
      "duration": 0,
      "containerType": "window",
      "containerSrc": "",
      "containerId": "",
      "containerName": ""
    }
  ]
}

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

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

দীর্ঘ অ্যানিমেশন ফ্রেম API

ব্রাউজার সমর্থন

  • ক্রোম: 123।
  • প্রান্ত: 123।
  • ফায়ারফক্স: সমর্থিত নয়।
  • সাফারি: সমর্থিত নয়।

উৎস

লং অ্যানিমেশন ফ্রেম এপিআই (LoAF) হল একটি নতুন এপিআই যা লং টাস্ক এপিআই-এর কিছু ত্রুটির সমাধান করতে চায় যাতে ডেভেলপাররা প্রতিক্রিয়াশীলতার সমস্যা মোকাবেলা করতে এবং INP উন্নত করতে আরও কার্যকরী অন্তর্দৃষ্টি পেতে সক্ষম হয়।

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

লং অ্যানিমেশন ফ্রেম API হল ব্লকিং কাজ পরিমাপের একটি বিকল্প পদ্ধতি। স্বতন্ত্র কাজগুলি পরিমাপ করার পরিবর্তে, লং অ্যানিমেশন ফ্রেম এপিআই—যেমন এর নাম থেকে বোঝা যায়— দীর্ঘ অ্যানিমেশন ফ্রেমগুলি পরিমাপ করে৷ একটি দীর্ঘ অ্যানিমেশন ফ্রেম হল যখন একটি রেন্ডারিং আপডেট 50 মিলিসেকেন্ডের বেশি বিলম্বিত হয় (লং টাস্ক API-এর থ্রেশহোল্ডের মতো)।

দীর্ঘ অ্যানিমেশন ফ্রেমগুলি PerformanceObserver সাথে দীর্ঘ কাজগুলির মতো একইভাবে পর্যবেক্ষণ করা যেতে পারে, তবে এর পরিবর্তে long-animation-frame ধরণটি দেখুন:

const observer = new PerformanceObserver((list) => {
  console.log(list.getEntries());
});

observer.observe({ type: 'long-animation-frame', buffered: true });

পূর্ববর্তী দীর্ঘ অ্যানিমেশন ফ্রেমগুলিও পারফরম্যান্স টাইমলাইন থেকে জিজ্ঞাসা করা যেতে পারে যেমন:

const loafs = performance.getEntriesByType('long-animation-frame');

যাইহোক, পারফরম্যান্স এন্ট্রিগুলির জন্য একটি maxBufferSize রয়েছে যার পরে নতুন এন্ট্রিগুলি বাদ দেওয়া হয়, তাই PerformanceObserver পদ্ধতিটি প্রস্তাবিত পদ্ধতি। long-animation-frame বাফার সাইজ 200-এ সেট করা হয়েছে, long-tasks মতো।

কাজের পরিবর্তে ফ্রেমের দিকে তাকানোর সুবিধা

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

দীর্ঘ কাজের ক্ষেত্রে এই বিকল্প দৃষ্টিভঙ্গির আরও একটি সুবিধা হল পুরো ফ্রেমের টাইমিং ব্রেকডাউন প্রদান করার ক্ষমতা। লং টাস্ক এপিআই এর মত একটি startTime এবং একটি duration অন্তর্ভুক্ত করার পরিবর্তে, LoAF ফ্রেমের সময়কালের বিভিন্ন অংশের আরও বিশদ বিভাজন অন্তর্ভুক্ত করে:

  • startTime : নেভিগেশন শুরুর সময়ের তুলনায় দীর্ঘ অ্যানিমেশন ফ্রেমের শুরুর সময়।
  • duration : দীর্ঘ অ্যানিমেশন ফ্রেমের সময়কাল (প্রেজেন্টেশনের সময় সহ নয়)।
  • renderStart : রেন্ডারিং চক্রের শুরুর সময়, যার মধ্যে requestAnimationFrame কলব্যাক, স্টাইল এবং লেআউট গণনা, রিসাইজ পর্যবেক্ষক এবং ইন্টারসেকশন পর্যবেক্ষক কলব্যাক অন্তর্ভুক্ত রয়েছে।
  • styleAndLayoutStart : শৈলী এবং বিন্যাস গণনায় অতিবাহিত সময়ের শুরু।
  • firstUIEventTimestamp : প্রথম UI ইভেন্টের সময় (মাউস/কীবোর্ড এবং তাই) এই ফ্রেমের সময় পরিচালনা করতে হবে।
  • blockingDuration : মিলিসেকেন্ডে সময়কাল যার জন্য অ্যানিমেশন ফ্রেম ব্লক করা হয়েছিল।

এই টাইমস্ট্যাম্পগুলি দীর্ঘ অ্যানিমেশন ফ্রেমকে সময়গুলিতে বিভক্ত করার অনুমতি দেয়:

টাইমিং হিসাব
শুরুর সময় startTime
শেষ সময় startTime + duration
কাজের সময়কাল renderStart ? renderStart - startTime : duration
রেন্ডারের সময়কাল renderStart ? (startTime + duration) - renderStart: 0
রেন্ডার: প্রাক-লেআউট সময়কাল styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0
রেন্ডার: শৈলী এবং বিন্যাস সময়কাল styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0

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

আরও ভালো অ্যাট্রিবিউশন

long-animation-frame এন্ট্রি টাইপটিতে প্রতিটি স্ক্রিপ্টের আরও ভাল অ্যাট্রিবিউশন ডেটা অন্তর্ভুক্ত থাকে যা একটি দীর্ঘ অ্যানিমেশন ফ্রেমে অবদান রাখে।

লং টাস্ক API-এর মতো, এটি অ্যাট্রিবিউশন এন্ট্রিগুলির একটি অ্যারেতে সরবরাহ করা হবে, যার প্রতিটি বিশদ:

  • একটি name এবং EntryType উভয়ই script প্রদান করবে।
  • একটি অর্থপূর্ণ invoker , যা নির্দেশ করে যে স্ক্রিপ্টটি কীভাবে কল করা হয়েছিল (উদাহরণস্বরূপ, 'IMG#id.onload' , 'Window.requestAnimationFrame' , বা 'Response.json.then' )।
  • স্ক্রিপ্ট এন্ট্রি পয়েন্টের invokerType :
    • user-callback : একটি ওয়েব প্ল্যাটফর্ম API থেকে নিবন্ধিত একটি পরিচিত কলব্যাক (উদাহরণস্বরূপ, setTimeout , requestAnimationFrame )।
    • event-listener : একটি প্ল্যাটফর্ম ইভেন্টের একজন শ্রোতা (উদাহরণস্বরূপ, click , load , keyup )।
    • resolve-promise : একটি প্ল্যাটফর্ম প্রতিশ্রুতির হ্যান্ডলার (উদাহরণস্বরূপ, fetch() । উল্লেখ্য যে প্রতিশ্রুতির ক্ষেত্রে, একই প্রতিশ্রুতির সমস্ত হ্যান্ডলারকে একটি "স্ক্রিপ্ট" হিসাবে একত্রে মিশ্রিত করা হয়) .
    • reject-promise : resolve-promise অনুযায়ী, কিন্তু প্রত্যাখ্যানের জন্য।
    • classic-script : স্ক্রিপ্ট মূল্যায়ন (উদাহরণস্বরূপ, <script> বা import() )
    • module-script : classic-script মতো, কিন্তু মডিউল স্ক্রিপ্টের জন্য।
  • সেই স্ক্রিপ্টের জন্য আলাদা টাইমিং ডেটা:
    • startTime : এন্ট্রি ফাংশন আহ্বান করা হয়েছে সময়.
    • duration : startTime এবং পরবর্তী মাইক্রোটাস্ক সারি প্রক্রিয়াকরণ শেষ হওয়ার মধ্যে সময়কাল।
    • executionStart : সংকলনের পরের সময়।
    • forcedStyleAndLayoutDuration : এই ফাংশনের ভিতরে বাধ্যতামূলক লেআউট এবং শৈলী প্রক্রিয়াকরণে ব্যয় করা মোট সময় ( থ্র্যাশিং দেখুন)।
    • pauseDuration : "পজ" সিঙ্ক্রোনাস অপারেশনে ব্যয় করা মোট সময় (সতর্ক, সিঙ্ক্রোনাস এক্সএইচআর)।
  • স্ক্রিপ্ট উত্স বিবরণ:
    • sourceURL : স্ক্রিপ্ট রিসোর্সের নাম যেখানে পাওয়া যায় (বা না পাওয়া গেলে খালি)।
    • sourceFunctionName : স্ক্রিপ্ট ফাংশনের নাম যেখানে উপলব্ধ (বা না পাওয়া গেলে খালি)।
    • sourceCharPosition : স্ক্রিপ্ট অক্ষর অবস্থান যেখানে উপলব্ধ (অথবা -1 যদি না পাওয়া যায়)।
  • windowAttribution : কন্টেইনার (শীর্ষ-স্তরের নথি, অথবা একটি <iframe> ) যে দীর্ঘ অ্যানিমেশন ফ্রেমটি ঘটেছে।
  • window : একই-অরিজিন উইন্ডোর একটি রেফারেন্স।

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

একটি long-animation-frame কর্মক্ষমতা এন্ট্রির উদাহরণ

একটি সম্পূর্ণ long-animation-frame কর্মক্ষমতা এন্ট্রি উদাহরণ, একটি একক স্ক্রিপ্ট সমন্বিত, হল:

{
  "blockingDuration": 0,
  "duration": 60,
  "entryType": "long-animation-frame",
  "firstUIEventTimestamp": 11801.099999999627,
  "name": "long-animation-frame",
  "renderStart": 11858.800000000745,
  "scripts": [
    {
      "duration": 45,
      "entryType": "script",
      "executionStart": 11803.199999999255,
      "forcedStyleAndLayoutDuration": 0,
      "invoker": "DOMWindow.onclick",
      "invokerType": "event-listener",
      "name": "script",
      "pauseDuration": 0,
      "sourceURL": "https://web.dev/js/index-ffde4443.js",
      "sourceFunctionName": "myClickHandler",
      "sourceCharPosition": 17796,
      "startTime": 11803.199999999255,
      "window": [Window object],
      "windowAttribution": "self"
    }
  ],
  "startTime": 11802.400000000373,
  "styleAndLayoutStart": 11858.800000000745
}

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

ক্ষেত্রে দীর্ঘ অ্যানিমেশন ফ্রেম API ব্যবহার করুন

Chrome DevTools এবং Lighthouse-এর মতো টুলগুলি-যদিও সমস্যাগুলি আবিষ্কার এবং পুনরুত্পাদন করার জন্য উপযোগী—এমন ল্যাব টুল যা ব্যবহারকারীর অভিজ্ঞতার গুরুত্বপূর্ণ দিকগুলি মিস করতে পারে যা শুধুমাত্র ফিল্ড ডেটা প্রদান করতে পারে।

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

দীর্ঘ অ্যানিমেশন ফ্রেম API সমর্থন সনাক্তকরণ বৈশিষ্ট্য

API সমর্থিত কিনা তা পরীক্ষা করতে আপনি নিম্নলিখিত কোড ব্যবহার করতে পারেন:

if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
  // Monitor LoAFs
}

লং অ্যানিমেশন ফ্রেম এপিআই-এর সবচেয়ে সুস্পষ্ট ব্যবহারের ক্ষেত্রে নেক্সট পেইন্ট (আইএনপি) সমস্যাগুলির ইন্টারঅ্যাকশন নির্ণয় এবং ঠিক করতে সাহায্য করা, এবং এটিই ছিল ক্রোম টিম এই APIটি তৈরি করার অন্যতম প্রধান কারণ। একটি ভাল INP হল যেখানে ফ্রেম আঁকা না হওয়া পর্যন্ত মিথস্ক্রিয়া থেকে 200 মিলিসেকেন্ড বা তার কম সময়ে সমস্ত ইন্টারঅ্যাকশনের প্রতিক্রিয়া জানানো হয় এবং যেহেতু লং অ্যানিমেশন ফ্রেম এপিআই 50ms বা তার বেশি সময় নেয় এমন সমস্ত ফ্রেম পরিমাপ করে, তাই বেশিরভাগ সমস্যাযুক্ত INP-এ আপনাকে নির্ণয় করতে সহায়তা করার জন্য LoAF ডেটা অন্তর্ভুক্ত করা উচিত। যারা মিথস্ক্রিয়া.

"INP LoAF" হল LoAF যা INP মিথস্ক্রিয়া অন্তর্ভুক্ত করে, যেমনটি নিম্নলিখিত চিত্রে দেখানো হয়েছে:

INP LoAF হাইলাইট করা সহ একটি পৃষ্ঠায় দীর্ঘ অ্যানিমেশন ফ্রেমের উদাহরণ।
একটি পৃষ্ঠায় অনেকগুলি LoAF থাকতে পারে, যার মধ্যে একটি INP মিথস্ক্রিয়া সম্পর্কিত।

কিছু ক্ষেত্রে একটি INP ইভেন্টের জন্য দুটি LoAFs স্প্যান করা সম্ভব-সাধারণত যদি ফ্রেমটি পূর্ববর্তী ফ্রেমের রেন্ডারিং অংশ শুরু করার পরে মিথস্ক্রিয়া ঘটে, এবং তাই ইভেন্ট হ্যান্ডলার এটি পরবর্তী ফ্রেমে প্রক্রিয়াজাত করে:

INP LoAF হাইলাইট করা সহ একটি পৃষ্ঠায় দীর্ঘ অ্যানিমেশন ফ্রেমের উদাহরণ।
একটি পৃষ্ঠায় অনেকগুলি LoAF থাকতে পারে, যার মধ্যে একটি INP মিথস্ক্রিয়া সম্পর্কিত।

এটি এমন কি সম্ভব যে এটি কিছু বিরল পরিস্থিতিতে দুটির বেশি LoAFs জুড়ে থাকতে পারে।

INP ইন্টারঅ্যাকশনের সাথে যুক্ত LoAF(গুলি) ডেটা রেকর্ড করা আপনাকে এটি নির্ণয় করতে সাহায্য করার জন্য INP মিথস্ক্রিয়া সম্পর্কে আরও অনেক তথ্য পেতে দেয়। ইনপুট বিলম্ব বোঝার জন্য এটি বিশেষভাবে সহায়ক: আপনি দেখতে পাচ্ছেন যে সেই ফ্রেমে অন্যান্য স্ক্রিপ্টগুলি কী চলছিল।

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

একটি INP এন্ট্রিকে এর সম্পর্কিত LoAF এন্ট্রি বা এন্ট্রিগুলির সাথে লিঙ্ক করার জন্য কোনও সরাসরি API নেই, যদিও প্রতিটির শুরু এবং শেষের সময় তুলনা করে কোডে এটি করা সম্ভব ( WhyNp উদাহরণ স্ক্রিপ্ট দেখুন)।

web-vitals লাইব্রেরিতে v4 থেকে INP অ্যাট্রিবিউশন ইন্টারফেসের longAnimationFramesEntries সম্পত্তিতে সমস্ত ছেদ করা LoAFs অন্তর্ভুক্ত রয়েছে।

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

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

আরও দীর্ঘ অ্যানিমেশন ডেটা অ্যানালিটিক্স এন্ডপয়েন্টে রিপোর্ট করুন

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

তাই শুধুমাত্র INP LoAF দেখে স্পটলাইট করার পরিবর্তে, আপনি সারাজীবন পৃষ্ঠার সমস্ত LoAF বিবেচনা করতে চাইতে পারেন:

অনেক LoAF সহ একটি পৃষ্ঠা, যার মধ্যে কিছু INP ইন্টারঅ্যাকশন না হলেও ইন্টারঅ্যাকশনের সময় ঘটে।
সমস্ত LoAFs এর দিকে তাকানো ভবিষ্যতে INP সমস্যা সনাক্ত করতে সাহায্য করতে পারে।

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

কিছু প্রস্তাবিত নিদর্শন অন্তর্ভুক্ত:

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

মিথস্ক্রিয়া সহ দীর্ঘ অ্যানিমেশন ফ্রেম পর্যবেক্ষণ করুন

শুধুমাত্র INP দীর্ঘ অ্যানিমেশন ফ্রেমের বাইরে অন্তর্দৃষ্টি পেতে, আপনি মিথস্ক্রিয়া সহ সমস্ত LoAFs দেখতে পারেন (যা একটি firstUIEventTimestamp মান উপস্থিতির দ্বারা সনাক্ত করা যেতে পারে)৷

এটি দুটিকে পারস্পরিক সম্পর্ক স্থাপনের চেষ্টা করার পরিবর্তে INP LoAFs পর্যবেক্ষণ করার একটি সহজ পদ্ধতি হতে পারে, যা আরও জটিল হতে পারে। বেশিরভাগ ক্ষেত্রে এটি একটি প্রদত্ত দর্শনের জন্য INP LoAF অন্তর্ভুক্ত করবে, এবং বিরল ক্ষেত্রে যখন এটি এখনও দীর্ঘ ইন্টারঅ্যাকশনগুলি প্রকাশ করে না যা ঠিক করা গুরুত্বপূর্ণ, কারণ সেগুলি অন্যান্য ব্যবহারকারীদের জন্য INP মিথস্ক্রিয়া হতে পারে।

নিম্নলিখিত কোডটি 150 মিলিসেকেন্ডের বেশি সমস্ত LoAF এন্ট্রি লগ করে যেখানে ফ্রেমের সময় একটি মিথস্ক্রিয়া ঘটেছে। 150 এখানে বেছে নেওয়া হয়েছে কারণ এটি 200 মিলিসেকেন্ডের "ভাল" INP থ্রেশহোল্ডের থেকে সামান্য কম। আপনি আপনার প্রয়োজনের উপর নির্ভর করে একটি উচ্চ বা নিম্ন মান চয়ন করতে পারেন।

const REPORTING_THRESHOLD_MS = 150;

const observer = new PerformanceObserver(list => {
    for (const entry of list.getEntries()) {
      if (entry.duration > REPORTING_THRESHOLD_MS &&
        entry.firstUIEventTimestamp > 0
      ) {
        // Example here logs to console, but could also report back to analytics
        console.log(entry);
      }
    }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

একটি নির্দিষ্ট থ্রেশহোল্ডের চেয়ে দীর্ঘ অ্যানিমেশন ফ্রেমগুলি পর্যবেক্ষণ করুন

আরেকটি কৌশল হল সমস্ত LoAFs নিরীক্ষণ করা এবং পরবর্তী বিশ্লেষণের জন্য একটি নির্দিষ্ট থ্রেশহোল্ডের চেয়ে বড়কে একটি অ্যানালিটিক্স এন্ডপয়েন্টে ফিরিয়ে দেওয়া:

const REPORTING_THRESHOLD_MS = 150;

const observer = new PerformanceObserver(list => {
  for (const entry of list.getEntries()) {
    if (entry.duration > REPORTING_THRESHOLD_MS) {
      // Example here logs to console, but could also report back to analytics
      console.log(entry);
    }
  }
});
observer.observe({ type: 'long-animation-frame', buffered: true });

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

সবচেয়ে খারাপ দীর্ঘ অ্যানিমেশন ফ্রেম পর্যবেক্ষণ করুন

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

MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];

const observer = new PerformanceObserver(list => {
  longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
    (a, b) => b.blockingDuration - a.blockingDuration
  ).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });

এই কৌশলগুলিও একত্রিত করা যেতে পারে - শুধুমাত্র 150 মিলিসেকেন্ডের বেশি মিথস্ক্রিয়া সহ 10টি খারাপ LoAFs দেখুন।

উপযুক্ত সময়ে ( আদর্শভাবে visibilitychange ইভেন্টে ) বিশ্লেষণে ফিরে যান। স্থানীয় পরীক্ষার জন্য আপনি পর্যায়ক্রমে console.table ব্যবহার করতে পারেন:

console.table(longestBlockingLoAFs);

দীর্ঘ অ্যানিমেশন ফ্রেমে সাধারণ নিদর্শন সনাক্ত করুন

একটি বিকল্প কৌশল হ'ল দীর্ঘ অ্যানিমেশন ফ্রেম এন্ট্রিগুলিতে সর্বাধিক প্রদর্শিত সাধারণ স্ক্রিপ্টগুলি দেখতে হবে। পুনরাবৃত্তি অপরাধীদের সনাক্ত করতে একটি স্ক্রিপ্ট এবং চরিত্রের অবস্থান স্তরে ডেটা আবার রিপোর্ট করা যেতে পারে।

এটি কাস্টমাইজযোগ্য প্ল্যাটফর্মের জন্য বিশেষভাবে ভাল কাজ করতে পারে যেখানে থিম বা প্লাগইনগুলি কর্মক্ষমতা সমস্যা সৃষ্টি করে এমন অনেক সাইট জুড়ে চিহ্নিত করা যেতে পারে।

দীর্ঘ অ্যানিমেশন ফ্রেমে সাধারণ স্ক্রিপ্ট-অথবা তৃতীয়-পক্ষের উৎপত্তি-এর সম্পাদনের সময় সংক্ষিপ্ত করা যেতে পারে এবং একটি সাইট বা সাইটগুলির একটি সংগ্রহ জুড়ে দীর্ঘ অ্যানিমেশন ফ্রেমে সাধারণ অবদানকারীদের সনাক্ত করতে আবার রিপোর্ট করা যেতে পারে। উদাহরণস্বরূপ URL গুলি দেখতে:

const observer = new PerformanceObserver(list => {
  const allScripts = list.getEntries().flatMap(entry => entry.scripts);
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));
  processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
  // Example here logs to console, but could also report back to analytics
  console.table(processedScripts);
});

observer.observe({type: 'long-animation-frame', buffered: true});

এবং এই আউটপুটের উদাহরণ হল:

(index) sourceURL count totalDuration
0 'https://example.consent.com/consent.js' 1 840
1 'https://example.com/js/analytics.js' 7 628
2 'https://example.chatapp.com/web-chat.js' 1 5

টুলিং এ লং অ্যানিমেশন ফ্রেম API ব্যবহার করুন

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

DevTools-এ সারফেস লং অ্যানিমেশন ফ্রেম ডেটা

আপনি performance.measure() API ব্যবহার করে DevTools-এ দীর্ঘ অ্যানিমেশন ফ্রেম দেখাতে পারেন, যা তারপরে পারফরম্যান্স ট্রেসে DevTools ব্যবহারকারী টাইমিং ট্র্যাকে প্রদর্শিত হয় যাতে দেখা যায় কর্মক্ষমতা উন্নতির জন্য আপনার প্রচেষ্টাকে কোথায় ফোকাস করতে হবে:

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    performance.measure('LoAF', {
      start: entry.startTime,
      end: entry.startTime + entry.duration,
    });
  }
});

observer.observe({ type: 'long-animation-frame', buffered: true });

দীর্ঘ মেয়াদে, এটি সম্ভবত DevTools-এর মধ্যেই অন্তর্ভুক্ত করা হবে, কিন্তু পূর্ববর্তী কোড স্নিপেট এর মধ্যেই এটিকে সেখানে প্রকাশ করার অনুমতি দেয়।

অন্যান্য ডেভেলপার টুলিং-এ দীর্ঘ অ্যানিমেশন ফ্রেম ডেটা ব্যবহার করুন

ওয়েব ভাইটালস এক্সটেনশনটি কার্য সম্পাদনের সমস্যাগুলি নির্ণয় করার জন্য সারাংশ ডিবাগ তথ্য লগ করার মান দেখিয়েছে

এটি এখন প্রতিটি INP কলব্যাক এবং প্রতিটি ইন্টারঅ্যাকশনের জন্য দীর্ঘ অ্যানিমেশন ফ্রেম ডেটাও সারফেস করে:

ওয়েব ভাইটালস এক্সটেনশন কনসোল লগিং।
ওয়েব ভাইটালস এক্সটেনশন কনসোল লগিং সারফেস LoAF ডেটা।

স্বয়ংক্রিয় পরীক্ষার সরঞ্জামগুলিতে দীর্ঘ অ্যানিমেশন ফ্রেম ডেটা ব্যবহার করুন

একইভাবে সিআই/সিডি পাইপলাইনে স্বয়ংক্রিয় পরীক্ষার সরঞ্জামগুলি বিভিন্ন টেস্ট স্যুট চালানোর সময় দীর্ঘ অ্যানিমেশন ফ্রেম পরিমাপ করে সম্ভাব্য কার্যক্ষমতা সংক্রান্ত সমস্যাগুলির বিবরণ প্রকাশ করতে পারে।

FAQ

এই API-তে প্রায়শই জিজ্ঞাসিত প্রশ্নগুলির মধ্যে রয়েছে:

কেন শুধু দীর্ঘ টাস্ক API এ প্রসারিত বা পুনরাবৃত্তি করবেন না?

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

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

কেন আমার স্ক্রিপ্ট এন্ট্রি নেই?

এটি ইঙ্গিত দিতে পারে যে দীর্ঘ অ্যানিমেশন ফ্রেমটি JavaScipt এর কারণে নয়, বরং বড় রেন্ডার কাজের কারণে।

এটি তখনও ঘটতে পারে যখন দীর্ঘ অ্যানিমেশন ফ্রেম জাভাস্ক্রিপ্টের কারণে হয় কিন্তু যেখানে পূর্বে উল্লেখ করা বিভিন্ন গোপনীয়তার কারণে স্ক্রিপ্ট অ্যাট্রিবিউশন প্রদান করা যায় না (প্রাথমিকভাবে জাভাস্ক্রিপ্ট পৃষ্ঠার মালিকানাধীন নয়)।

কেন আমি স্ক্রিপ্ট এন্ট্রি আছে কিন্তু কোন, বা সীমিত, উৎস তথ্য আছে?

এটি বিভিন্ন কারণে ঘটতে পারে, যার মধ্যে নির্দেশ করার জন্য একটি ভাল উত্স না থাকা সহ।

no-cors cross-origin স্ক্রিপ্টগুলির জন্যও স্ক্রিপ্টের তথ্য সীমিত থাকবে, যদিও <script> কলে crossOrigin = "anonymous" যোগ করে CORS ব্যবহার করে সেই স্ক্রিপ্টগুলি আনার মাধ্যমে এটি সমাধান করা যেতে পারে।

উদাহরণস্বরূপ, পৃষ্ঠায় যোগ করার জন্য ডিফল্ট Google ট্যাগ ম্যানেজার স্ক্রিপ্ট:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

j.crossOrigin = "anonymous" যোগ করার জন্য উন্নত করা যেতে পারে যাতে GTM-এর জন্য সম্পূর্ণ অ্যাট্রিবিউশন বিশদ প্রদান করা যায়

এটি কি লং টাস্ক API প্রতিস্থাপন করবে?

যদিও আমরা বিশ্বাস করি লং অ্যানিমেশন ফ্রেম এপিআই দীর্ঘ কাজ পরিমাপ করার জন্য একটি ভাল, আরও সম্পূর্ণ API, এই সময়ে, লং টাস্ক এপিআইকে অবমূল্যায়ন করার কোন পরিকল্পনা নেই।

প্রতিক্রিয়া চেয়েছিলেন

গিটহাব ইস্যু তালিকায় প্রতিক্রিয়া প্রদান করা যেতে পারে, বা ক্রোমের এপিআই বাস্তবায়নে বাগগুলি ক্রোমের ইস্যু ট্র্যাকারে ফাইল করা যেতে পারে।

উপসংহার

লং অ্যানিমেশন ফ্রেম API হল একটি উত্তেজনাপূর্ণ নতুন API যা আগের লং টাস্ক API এর তুলনায় অনেক সম্ভাব্য সুবিধা সহ।

এটি INP দ্বারা পরিমাপ করা প্রতিক্রিয়াশীলতার সমস্যাগুলি সমাধানের জন্য একটি মূল হাতিয়ার হিসাবে প্রমাণিত হচ্ছে৷ INP হল অপ্টিমাইজ করার জন্য একটি চ্যালেঞ্জিং মেট্রিক এবং এই API হল একটি উপায় যা Chrome টিম ডেভেলপারদের জন্য সমস্যাগুলি সনাক্ত করা এবং সমাধান করা সহজ করতে চাইছে৷

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

স্বীকৃতি

আনস্প্ল্যাশে হেনরি বি- এর থাম্বনেইল ছবি।