ভালো রেন্ডারিং পারফরম্যান্সের জন্য জ্যাঙ্ক বাস্টিং

টম উইল্টজিয়াস
Tom Wiltzius

ভূমিকা

অ্যানিমেশন, ট্রানজিশন এবং অন্যান্য ছোট UI প্রভাবগুলি করার সময় আপনি আপনার ওয়েব অ্যাপটিকে প্রতিক্রিয়াশীল এবং মসৃণ মনে করতে চান৷ এই প্রভাবগুলি ঝাঁকুনি-মুক্ত কিনা তা নিশ্চিত করার অর্থ একটি "নেটিভ" অনুভূতি বা একটি ক্লাঙ্কি, আনপোলিশডের মধ্যে পার্থক্য বোঝাতে পারে।

ব্রাউজারে রেন্ডারিং পারফরম্যান্স অপ্টিমাইজেশন কভার করা নিবন্ধগুলির একটি সিরিজের মধ্যে এটি প্রথম। জিনিসগুলি শুরু করতে, আমরা কভার করব কেন মসৃণ অ্যানিমেশন কঠিন এবং এটি অর্জনের জন্য কী ঘটতে হবে, সেইসাথে কয়েকটি সহজ সেরা অনুশীলন। এই ধারণাগুলির মধ্যে অনেকগুলি মূলত "জ্যাঙ্ক বুস্টারস" এ উপস্থাপন করা হয়েছিল, একটি টক ন্যাট ডুকা এবং আমি এই বছর Google I/O টক ( ভিডিও ) এ দিয়েছিলাম৷

ভি-সিঙ্ক উপস্থাপন করা হচ্ছে

পিসি গেমাররা এই শব্দটির সাথে পরিচিত হতে পারে, তবে এটি ওয়েবে অস্বাভাবিক: ভি-সিঙ্ক কী?

আপনার ফোনের ডিসপ্লে বিবেচনা করুন: এটি নিয়মিত বিরতিতে রিফ্রেশ হয়, সাধারণত (কিন্তু সবসময় নয়!) সেকেন্ডে প্রায় 60 বার। ভি-সিঙ্ক (বা উল্লম্ব সিঙ্ক্রোনাইজেশন) শুধুমাত্র স্ক্রিন রিফ্রেশের মধ্যে নতুন ফ্রেম তৈরি করার অনুশীলনকে বোঝায়। আপনি এটিকে স্ক্রীন বাফারে ডেটা লেখার প্রক্রিয়া এবং ডিসপ্লেতে রাখার জন্য সেই ডেটা পড়ার অপারেটিং সিস্টেমের মধ্যে একটি রেসের অবস্থার মতো মনে করতে পারেন। আমরা চাই বাফার করা ফ্রেমের বিষয়বস্তু এই রিফ্রেশের মধ্যে পরিবর্তন হোক, তাদের সময় নয়; অন্যথায় মনিটর একটি ফ্রেমের অর্ধেক এবং অন্য ফ্রেমের অর্ধেক প্রদর্শন করবে, যার ফলে " টিয়ার " হবে।

একটি মসৃণ অ্যানিমেশন পেতে আপনার প্রতিবার স্ক্রীন রিফ্রেশ হওয়ার জন্য একটি নতুন ফ্রেম প্রস্তুত হতে হবে। এর দুটি বড় প্রভাব রয়েছে: ফ্রেম টাইমিং (অর্থাৎ, যখন ফ্রেমটি প্রস্তুত হতে হবে) এবং ফ্রেম বাজেট (অর্থাৎ, ব্রাউজারকে কতক্ষণ একটি ফ্রেম তৈরি করতে হবে)। একটি ফ্রেম (60Hz স্ক্রিনে ~16ms) সম্পূর্ণ করার জন্য আপনার কাছে শুধুমাত্র স্ক্রীন রিফ্রেশের মধ্যে সময় আছে এবং আপনি শেষটি স্ক্রিনে রাখার সাথে সাথে পরবর্তী ফ্রেম তৈরি করা শুরু করতে চান।

টাইমিং হল সবকিছু: অনুরোধ অ্যানিমেশন ফ্রেম

অনেক ওয়েব ডেভেলপার অ্যানিমেশন তৈরি করতে প্রতি 16 মিলিসেকেন্ডে setInterval বা setTimeout ব্যবহার করে। এটি বিভিন্ন কারণে একটি সমস্যা (এবং আমরা এক মিনিটের মধ্যে আরও আলোচনা করব), তবে বিশেষ উদ্বেগের বিষয় হল:

  • জাভাস্ক্রিপ্ট থেকে টাইমার রেজোলিউশন শুধুমাত্র কয়েক মিলিসেকেন্ডের ক্রম অনুসারে
  • বিভিন্ন ডিভাইসের বিভিন্ন রিফ্রেশ হার আছে

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

বিভিন্ন ডিসপ্লেতে বিভিন্ন রিফ্রেশ রেট থাকে: 60Hz সাধারণ, কিন্তু কিছু ফোন 59Hz হয়, কিছু ল্যাপটপ লো-পাওয়ার মোডে 50Hz এ নেমে যায়, কিছু ডেস্কটপ মনিটর 70Hz হয়।

রেন্ডারিং পারফরম্যান্স নিয়ে আলোচনা করার সময় আমরা ফ্রেম প্রতি সেকেন্ডে (FPS) ফোকাস করার প্রবণতা রাখি, কিন্তু ভিন্নতা আরও বড় সমস্যা হতে পারে। আমাদের চোখ অ্যানিমেশনের ক্ষুদ্র, অনিয়মিত হিচগুলি লক্ষ্য করে যা একটি খারাপ সময়মতো অ্যানিমেশন তৈরি করতে পারে।

সঠিকভাবে টাইমড অ্যানিমেশন ফ্রেম পাওয়ার উপায় হল requestAnimationFrame । আপনি যখন এই API ব্যবহার করেন, আপনি ব্রাউজারকে একটি অ্যানিমেশন ফ্রেমের জন্য জিজ্ঞাসা করছেন। ব্রাউজার শীঘ্রই একটি নতুন ফ্রেম তৈরি করতে যাচ্ছে তখন আপনার কলব্যাক কল করা হবে। রিফ্রেশ রেট যাই হোক না কেন এটি ঘটে।

requestAnimationFrame অন্যান্য চমৎকার বৈশিষ্ট্যও রয়েছে:

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

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

ফ্রেম বাজেট

যেহেতু আমরা প্রতিটি স্ক্রীন রিফ্রেশে একটি নতুন ফ্রেম প্রস্তুত করতে চাই, তাই একটি নতুন ফ্রেম তৈরি করার জন্য সমস্ত কাজ করার জন্য রিফ্রেশের মধ্যে শুধুমাত্র সময় আছে। একটি 60Hz ডিসপ্লেতে, এর অর্থ হল আমরা সমস্ত জাভাস্ক্রিপ্ট চালানো, লেআউট সম্পাদন, পেইন্ট এবং ফ্রেমটি বের করার জন্য ব্রাউজারকে যা কিছু করতে হবে তার জন্য প্রায় 16ms পেয়েছি। এর মানে হল যদি আপনার requestAnimationFrame কলব্যাকের ভিতরে জাভাস্ক্রিপ্টটি 16ms এর বেশি সময় নেয়, তাহলে আপনার v-sync-এর জন্য সময়মতো একটি ফ্রেম তৈরি করার কোনো আশা নেই!

16ms খুব বেশি সময় নয়। সৌভাগ্যবশত ক্রোমের বিকাশকারী সরঞ্জামগুলি আপনাকে অ্যানিমেশনফ্রেম কলব্যাকের অনুরোধের সময় আপনার ফ্রেমের বাজেট উড়িয়ে দিলে তা ট্র্যাক করতে সাহায্য করতে পারে৷

ডেভ টুলস টাইমলাইন খোলা এবং এই অ্যানিমেশনের একটি রেকর্ডিং দ্রুত কাজ করে দেখায় যে অ্যানিমেশন করার সময় আমরা বাজেটের চেয়ে বেশি। টাইমলাইনে "ফ্রেম" এ স্যুইচ করুন এবং একবার দেখুন:

অনেক বেশি লেআউট সহ একটি ডেমো৷
অনেক বেশি লেআউট সহ একটি ডেমো৷

সেই অনুরোধ অ্যানিমেশনফ্রেম (rAF) কলব্যাকগুলি > 200ms নিচ্ছে৷ এটি প্রতি 16 মিসে একটি ফ্রেমে টিক আউট করার জন্য খুব দীর্ঘ মাত্রার একটি আদেশ! এই দীর্ঘ RAF কলব্যাকগুলির মধ্যে একটি খুললে ভিতরে কী ঘটছে তা প্রকাশ করে: এই ক্ষেত্রে, প্রচুর লেআউট।

পলের ভিডিও রিলেআউটের নির্দিষ্ট কারণ (এটি scrollTop পড়ছে) এবং কীভাবে এটি এড়ানো যায় সে সম্পর্কে আরও বিশদে যায়। কিন্তু এখানে বিন্দু হল যে আপনি কলব্যাকে ডুব দিতে পারেন এবং তদন্ত করতে পারেন যে এত সময় লাগছে।

অনেক কম লেআউট সহ একটি আপডেট ডেমো
অনেক কম লেআউট সহ একটি আপডেট ডেমো

16ms ফ্রেম বার লক্ষ্য করুন. ফ্রেমের সেই ফাঁকা জায়গাটি হল হেডরুম যা আপনাকে আরও কাজ করতে হবে (অথবা ব্রাউজারটিকে পটভূমিতে কাজ করতে দিন)। যে ফাঁকা জায়গা একটি ভাল জিনিস.

জ্যাঙ্কের অন্যান্য উৎস

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

এই পরিস্থিতিগুলি এড়াতে কোনও জাদু বুলেট নেই, তবে সাফল্যের জন্য নিজেকে সেট আপ করার জন্য কয়েকটি স্থাপত্য সেরা অনুশীলন রয়েছে:

  • ইনপুট হ্যান্ডলারে অনেক প্রক্রিয়াকরণ করবেন না! প্রচুর জেএস করা বা পুরো পৃষ্ঠাটি পুনর্বিন্যাস করার চেষ্টা করা যেমন একটি অনস্ক্রোল হ্যান্ডলার ভয়ানক ঝাঁকুনির একটি খুব সাধারণ কারণ।
  • আপনার আরএএফ কলব্যাক বা ওয়েব ওয়ার্কারগুলিতে যতটা সম্ভব প্রক্রিয়াকরণ (পড়ুন: যে কোনও কিছু চালাতে দীর্ঘ সময় লাগবে) চাপুন।
  • আপনি যদি আরএএফ কলব্যাকে কাজটি ঠেলে দেন, তবে এটিকে খণ্ডিত করার চেষ্টা করুন যাতে আপনি প্রতিটি ফ্রেমের সামান্য প্রসেস করছেন বা একটি গুরুত্বপূর্ণ অ্যানিমেশন শেষ না হওয়া পর্যন্ত এটি বিলম্বিত করতে পারেন -- এইভাবে আপনি ছোট আরএএফ কলব্যাক চালানো চালিয়ে যেতে পারেন এবং মসৃণভাবে অ্যানিমেট করতে পারেন .

ইনপুট হ্যান্ডলারের পরিবর্তে রিকোয়েস্ট অ্যানিমেশনফ্রেম কলব্যাকে প্রসেসিং কীভাবে ঠেলে দেওয়া যায় তা কভার করার জন্য একটি দুর্দান্ত টিউটোরিয়ালের জন্য, পল লুইসের নিবন্ধটি দেখুন অনুরোধ অ্যানিমেশনফ্রেম সহ Leaner, Meaner, Faster Animations .

CSS অ্যানিমেশন

আপনার ইভেন্ট এবং আরএএফ কলব্যাকগুলিতে লাইটওয়েট জেএসের চেয়ে ভাল কী? কোন JS.

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

জ্যাঙ্কের উপরোক্ত বিভাগে একটি অন্তর্নিহিত বিবৃতি রয়েছে: ব্রাউজারগুলি একবারে শুধুমাত্র একটি কাজ করতে পারে। এটি কঠোরভাবে সত্য নয়, তবে এটি একটি ভাল কাজ করার অনুমান: যে কোনও নির্দিষ্ট সময়ে ব্রাউজারটি JS চালাতে পারে, লেআউট সম্পাদন করতে পারে বা পেইন্টিং করতে পারে, কিন্তু একবারে শুধুমাত্র একটি। এটি Dev Tools-এর টাইমলাইন ভিউতে যাচাই করা যেতে পারে। এই নিয়মের ব্যতিক্রমগুলির মধ্যে একটি হল অ্যান্ড্রয়েডের জন্য ক্রোমে CSS অ্যানিমেশন (এবং শীঘ্রই ডেস্কটপ ক্রোম, যদিও এখনও নেই)।

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

  // see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ for info on rAF polyfills
  rAF = window.requestAnimationFrame;

  var degrees = 0;
  function update(timestamp) {
    document.querySelector('#foo').style.webkitTransform = "rotate(" + degrees + "deg)";
    console.log('updated to degrees ' + degrees);
    degrees = degrees + 1;
    rAF(update);
  }
  rAF(update);

আপনি যদি বোতামে ক্লিক করেন তাহলে জাভাস্ক্রিপ্ট 180ms পর্যন্ত চলে, যার ফলে জ্যাঙ্ক হয়। কিন্তু এর পরিবর্তে যদি আমরা সেই অ্যানিমেশনটিকে CSS অ্যানিমেশন দিয়ে চালাই তাহলে জ্যাঙ্ক আর ঘটবে না।

(এই লেখার সময় মনে রাখবেন, CSS অ্যানিমেশন শুধুমাত্র অ্যান্ড্রয়েডের জন্য ক্রোমে জ্যাঙ্ক-মুক্ত, ডেস্কটপ ক্রোমে নয়।)

  /* tools like Modernizr (http://modernizr.com/) can help with CSS polyfills */
  #foo {
    +animation-duration: 3s;
    +animation-timing-function: linear;
    +animation-animation-iteration-count: infinite;
    +animation-animation-name: rotate;
  }

  @+keyframes: rotate; {
    from {
      +transform: rotate(0deg);
    }
    to {
      +transform: rotate(360deg);
    }
  }

CSS অ্যানিমেশন ব্যবহার করার বিষয়ে আরও তথ্যের জন্য, MDN-এ এই ধরনের নিবন্ধগুলি দেখুন।

শেষ করি

এর সংক্ষিপ্ততা হল:

  1. অ্যানিমেটিং করার সময়, প্রতিটি স্ক্রিনের রিফ্রেশের জন্য ফ্রেম তৈরি করা গুরুত্বপূর্ণ। Vsync'd অ্যানিমেশন একটি অ্যাপের অনুভূতিতে বিশাল ইতিবাচক প্রভাব ফেলে।
  2. Chrome এবং অন্যান্য আধুনিক ব্রাউজারে vsync'd অ্যানিমেশন পাওয়ার সর্বোত্তম উপায় হল CSS অ্যানিমেশন ব্যবহার করা। যখন আপনার CSS অ্যানিমেশনের তুলনায় আরও বেশি নমনীয়তার প্রয়োজন হয়, তখন সর্বোত্তম কৌশল হল অনুরোধ অ্যানিমেশনফ্রেম-ভিত্তিক অ্যানিমেশন।
  3. আরএএফ অ্যানিমেশনগুলিকে স্বাস্থ্যকর এবং সুখী রাখতে, নিশ্চিত করুন যে অন্যান্য ইভেন্ট হ্যান্ডলাররা আপনার আরএএফ কলব্যাক চলার পথে বাধা পাচ্ছে না এবং আরএএফ কলব্যাকগুলি ছোট রাখুন (<15ms)।

সবশেষে, vsync'd অ্যানিমেশন শুধুমাত্র সাধারণ UI অ্যানিমেশনের ক্ষেত্রে প্রযোজ্য নয় -- এটি Canvas2D অ্যানিমেশন, WebGL অ্যানিমেশন, এমনকি স্ট্যাটিক পৃষ্ঠাগুলিতে স্ক্রল করার ক্ষেত্রেও প্রযোজ্য। এই সিরিজের পরবর্তী নিবন্ধে আমরা এই ধারণাগুলিকে মাথায় রেখে স্ক্রলিং পারফরম্যান্সে খনন করব।

হ্যাপি অ্যানিমেটিং!

তথ্যসূত্র