ব্যবহারকারীর ইনপুটে দ্রুত সাড়া দেয় এমন ওয়েবসাইট তৈরি করা ওয়েব পারফরম্যান্সের অন্যতম কঠিন একটি দিক—এবং ওয়েব ডেভেলপারদের এই চ্যালেঞ্জ মোকাবিলায় সাহায্য করতে ক্রোম টিম কঠোর পরিশ্রম করে আসছে। এই বছরই ঘোষণা করা হয়েছে যে , ‘ইন্টারঅ্যাকশন টু নেক্সট পেইন্ট (INP)’ মেট্রিকটি পরীক্ষামূলক পর্যায় থেকে ‘পেন্ডিং’ পর্যায়ে উন্নীত হবে। এটি এখন ২০২৪ সালের মার্চ মাসে ‘ফার্স্ট ইনপুট ডিলে (FID)’-কে প্রতিস্থাপন করে একটি ‘কোর ওয়েব ভাইটাল’ হিসেবে আত্মপ্রকাশ করতে চলেছে।
ওয়েব ডেভেলপারদের ওয়েবসাইটগুলোকে যথাসম্ভব দ্রুতগতির করে তুলতে সাহায্য করে এমন নতুন এপিআই (API) সরবরাহের চলমান প্রচেষ্টার অংশ হিসেবে, ক্রোম টিম বর্তমানে ক্রোমের ১১৫তম সংস্করণ থেকে scheduler.yield এর একটি অরিজিন ট্রায়াল চালাচ্ছে। scheduler.yield হলো শিডিউলার এপিআই-এর একটি প্রস্তাবিত নতুন সংযোজন, যা প্রচলিত পদ্ধতিগুলোর চেয়ে মেইন থ্রেডে নিয়ন্ত্রণ ফিরিয়ে দেওয়ার জন্য একটি সহজতর ও উন্নততর উপায় প্রদান করে।
ফলনের উপর
জাভাস্ক্রিপ্ট টাস্ক পরিচালনার জন্য রান-টু-কমপ্লিশন মডেল ব্যবহার করে। এর মানে হলো, যখন কোনো টাস্ক মেইন থ্রেডে চলে, তখন সেটি সম্পূর্ণ হতে যতক্ষণ প্রয়োজন ততক্ষণ চলে। টাস্কটি সম্পূর্ণ হলে, নিয়ন্ত্রণ মেইন থ্রেডে ফিরে আসে , যা মেইন থ্রেডকে কিউ-তে থাকা পরবর্তী টাস্কটি প্রসেস করার সুযোগ দেয়।
চরম কিছু ক্ষেত্র ছাড়া, যখন কোনো কাজ কখনোই শেষ হয় না—যেমন, একটি অসীম লুপ (infinite loop)—জাভাস্ক্রিপ্টের টাস্ক শিডিউলিং লজিকের একটি অনিবার্য অংশ হলো ইয়েল্ডিং (yielding)। এটি ঘটবেই , শুধু সময়ের অপেক্ষা, এবং দেরির চেয়ে তাড়াতাড়ি হওয়াই শ্রেয়। যখন কোনো কাজ চলতে খুব বেশি সময় নেয়—সুনির্দিষ্টভাবে বলতে গেলে ৫০ মিলিসেকেন্ডের বেশি—তখন সেগুলোকে দীর্ঘ কাজ (long tasks) হিসেবে গণ্য করা হয়।
দীর্ঘ কাজগুলো পেজের রেসপন্সিভনেস কমে যাওয়ার একটি কারণ, কারণ এগুলো ব্যবহারকারীর ইনপুটে সাড়া দেওয়ার ক্ষেত্রে ব্রাউজারের ক্ষমতাকে বিলম্বিত করে। যত ঘন ঘন দীর্ঘ কাজগুলো ঘটে—এবং যত বেশি সময় ধরে চলে—ততই ব্যবহারকারীদের কাছে পেজটিকে ধীরগতির মনে হওয়ার, বা এমনকি এটি পুরোপুরি অচল হয়ে গেছে বলে মনে হওয়ার সম্ভাবনা বেড়ে যায়।
তবে, আপনার কোড ব্রাউজারে কোনো টাস্ক শুরু করলেই যে মূল থ্রেডে নিয়ন্ত্রণ ফিরিয়ে দেওয়ার আগে সেই টাস্কটি শেষ হওয়া পর্যন্ত অপেক্ষা করতে হবে, এমনটা নয়। কোনো টাস্কের মধ্যে স্পষ্টভাবে নিয়ন্ত্রণ ফিরিয়ে দেওয়ার (yield) মাধ্যমে আপনি একটি পেজে ব্যবহারকারীর ইনপুটের প্রতি রেসপন্সিভনেস উন্নত করতে পারেন, যা টাস্কটিকে ভেঙে পরবর্তী উপলব্ধ সুযোগে শেষ করার জন্য প্রস্তুত করে। এর ফলে, দীর্ঘ টাস্কগুলো শেষ হওয়ার জন্য অপেক্ষা করার চেয়ে অন্যান্য টাস্কগুলো মূল থ্রেডে আরও দ্রুত কাজ করার সুযোগ পায়।

যখন আপনি স্পষ্টভাবে ইয়েল্ড (yield) করেন, তখন আপনি ব্রাউজারকে বলছেন, "আমি বুঝতে পারছি যে আমি যে কাজটি করতে যাচ্ছি তাতে কিছুটা সময় লাগতে পারে, এবং আমি চাই না যে ব্যবহারকারীর ইনপুট বা অন্যান্য গুরুত্বপূর্ণ কাজের প্রতিক্রিয়া জানানোর আগে তোমাকে সেই পুরো কাজটি করতে হোক"। এটি একজন ডেভেলপারের টুলবক্সের একটি মূল্যবান হাতিয়ার যা ব্যবহারকারীর অভিজ্ঞতা উন্নত করতে অনেক দূর এগিয়ে নিয়ে যেতে পারে।
বর্তমান ফলন কৌশলগুলির সমস্যা
ইয়েল্ড করার একটি প্রচলিত পদ্ধতি হলো setTimeout সাথে টাইমআউট ভ্যালু 0 ব্যবহার করা । এটি কাজ করে কারণ setTimeout এ পাস করা কলব্যাকটি অবশিষ্ট কাজকে একটি পৃথক টাস্কে স্থানান্তর করে, যা পরবর্তী সম্পাদনের জন্য কিউতে যুক্ত থাকে। ব্রাউজারের নিজে থেকে ইয়েল্ড করার জন্য অপেক্ষা না করে, আপনি বলছেন "কাজের এই বড় অংশটিকে ছোট ছোট অংশে ভাগ করে নাও"।
তবে, setTimeout ব্যবহার করে ইয়েল্ড করার একটি সম্ভাব্য অনাকাঙ্ক্ষিত পার্শ্বপ্রতিক্রিয়া রয়েছে: ইয়েল্ড পয়েন্টের পরের কাজটি টাস্ক কিউ-এর একদম শেষে চলে যাবে। ব্যবহারকারীর ইন্টারঅ্যাকশনের মাধ্যমে শিডিউল করা টাস্কগুলো নিয়ম অনুযায়ী কিউ-এর সামনেই চলে আসবে—কিন্তু স্পষ্টভাবে ইয়েল্ড করার পর আপনি যে অবশিষ্ট কাজটি করতে চেয়েছিলেন, সেটি তার আগে কিউ-তে থাকা প্রতিযোগী উৎসের অন্যান্য টাস্কের কারণে আরও বিলম্বিত হতে পারে।
এটি বাস্তবে দেখতে, এই কোডপেন ডেমোটি ব্যবহার করে দেখুন —অথবা নিচের এমবেডেড সংস্করণটিতে এটি নিয়ে পরীক্ষা করুন। ডেমোটিতে ক্লিক করার জন্য কয়েকটি বাটন এবং সেগুলোর নিচে একটি বক্স রয়েছে, যা টাস্ক রান হওয়ার সময় লগ করে রাখে। পেজটিতে প্রবেশ করার পর, নিম্নলিখিত কাজগুলো করুন:
- উপরে থাকা ‘Run tasks periods’ লেখা বাটনটিতে ক্লিক করুন, যা নির্দিষ্ট সময় পরপর ব্লকিং টাস্ক চালানোর জন্য সময়সূচী নির্ধারণ করবে। আপনি যখন এই বাটনটিতে ক্লিক করবেন, তখন টাস্ক লগে ‘Ran blocking task with
setIntervalলেখা কয়েকটি বার্তা যুক্ত হবে। - এরপর, 'Run loop, yielding with
setTimeouton each iteration ' লেবেলযুক্ত বোতামটিতে ক্লিক করুন।
আপনি লক্ষ্য করবেন যে ডেমোর নীচের বক্সটিতে এইরকম কিছু লেখা থাকবে:
Processing loop item 1
Processing loop item 2
Ran blocking task via setInterval
Processing loop item 3
Ran blocking task via setInterval
Processing loop item 4
Ran blocking task via setInterval
Processing loop item 5
Ran blocking task via setInterval
Ran blocking task via setInterval
এই আউটপুটটি "টাস্ক কিউ-এর শেষ" আচরণটি প্রদর্শন করে, যা setTimeout ব্যবহার করে yield করার সময় ঘটে। যে লুপটি চলে, সেটি পাঁচটি আইটেম প্রসেস করে এবং প্রতিটি প্রসেস হয়ে যাওয়ার পর setTimeout ব্যবহার করে yield করে।
এটি ওয়েবের একটি সাধারণ সমস্যা তুলে ধরে: কোনো স্ক্রিপ্ট—বিশেষ করে কোনো থার্ড-পার্টি স্ক্রিপ্ট—একটি টাইমার ফাংশন রেজিস্টার করে, যা একটি নির্দিষ্ট বিরতিতে কাজ চালায়। setTimeout ব্যবহার করে yield করার ফলে যে "টাস্ক কিউ-এর শেষ" আচরণটি ঘটে, তার মানে হলো yield করার পরে লুপের বাকি থাকা কাজের আগে অন্যান্য টাস্ক সোর্সের কাজ কিউ-তে চলে আসতে পারে।
আপনার অ্যাপ্লিকেশনের উপর নির্ভর করে, এটি একটি কাঙ্ক্ষিত ফলাফল হতেও পারে বা নাও হতে পারে—কিন্তু অনেক ক্ষেত্রে, এই আচরণের কারণেই ডেভেলপাররা এত সহজে মেইন থ্রেডের নিয়ন্ত্রণ ছেড়ে দিতে অনিচ্ছুক বোধ করেন। ইয়েল্ডিং (Yielding) ভালো, কারণ এর ফলে ব্যবহারকারীর ইন্টারঅ্যাকশনগুলো আগে চলার সুযোগ পায়, কিন্তু এটি ব্যবহারকারীর ইন্টারঅ্যাকশন-বহির্ভূত অন্যান্য কাজকেও মেইন থ্রেডে সময় পেতে সাহায্য করে। এটি একটি বাস্তব সমস্যা—কিন্তু scheduler.yield এটি সমাধানে সাহায্য করতে পারে!
scheduler.yield প্রবেশ করুন
ক্রোমের ১১৫তম সংস্করণ থেকে scheduler.yield একটি পরীক্ষামূলক ওয়েব প্ল্যাটফর্ম ফিচার হিসেবে ফ্ল্যাগের আড়ালে উপলব্ধ রয়েছে। আপনার মনে একটি প্রশ্ন আসতে পারে যে, " setTimeout যখন yield-এর কাজটি করেই দেয়, তখন এর জন্য আমার একটি বিশেষ ফাংশনের প্রয়োজন কেন?"
এটা মনে রাখা দরকার যে, `eilling` (ইল্ড করা) setTimeout এর কোনো ডিজাইন লক্ষ্য ছিল না, বরং এটি ভবিষ্যতে কোনো এক সময়ে একটি কলব্যাক চালানোর জন্য সময়সূচি নির্ধারণ করার একটি চমৎকার পার্শ্ব-প্রতিক্রিয়া—এমনকি টাইমআউটের মান 0 নির্দিষ্ট করা থাকলেও। তবে, আরও গুরুত্বপূর্ণ যে বিষয়টি মনে রাখতে হবে তা হলো, setTimeout সাথে `eilling` করলে অবশিষ্ট কাজ টাস্ক কিউ-এর পেছনে চলে যায়। ডিফল্টভাবে, scheduler.yield অবশিষ্ট কাজকে কিউ-এর সামনে পাঠায়। এর মানে হলো, `eilling` করার ঠিক পরেই আপনি যে কাজটি পুনরায় শুরু করতে চেয়েছিলেন, তা অন্য উৎস থেকে আসা টাস্কের কাছে পিছিয়ে পড়বে না (ব্যবহারকারীর ইন্টারঅ্যাকশন এর একটি উল্লেখযোগ্য ব্যতিক্রম)।
scheduler.yield হলো এমন একটি ফাংশন যা কল করা হলে মেইন থ্রেডকে সুযোগ দেয় এবং একটি Promise রিটার্ন করে। এর মানে হলো, আপনি একটি async ফাংশনের মধ্যে এটিকে await করতে পারেন:
async function yieldy () {
// Do some work...
// ...
// Yield!
await scheduler.yield();
// Do some more work...
// ...
}
scheduler.yield এর কার্যকারিতা দেখতে, নিম্নলিখিতগুলি করুন:
-
chrome://flagsএ যান। - এক্সপেরিমেন্টাল ওয়েব প্ল্যাটফর্ম ফিচারস এক্সপেরিমেন্টটি সক্রিয় করুন। এটি করার পর আপনাকে ক্রোম রিস্টার্ট করতে হতে পারে।
- ডেমো পৃষ্ঠায় যান অথবা এই তালিকার পরে এর নিম্নলিখিত এমবেডেড সংস্করণটি ব্যবহার করুন।
- উপরে থাকা ‘Run tasks periodically’ লেখা বাটনটিতে ক্লিক করুন।
- অবশেষে, "Run loop, yielding with
scheduler.yieldon each iteration" লেবেলযুক্ত বোতামটি ক্লিক করুন।
পৃষ্ঠার নীচের বাক্সে আউটপুটটি দেখতে অনেকটা এইরকম হবে:
Processing loop item 1
Processing loop item 2
Processing loop item 3
Processing loop item 4
Processing loop item 5
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
Ran blocking task via setInterval
setTimeout ব্যবহার করে yield করা ডেমোটির থেকে ভিন্ন, আপনি দেখতে পারেন যে লুপটি—যদিও এটি প্রতিটি পুনরাবৃত্তির পরে yield করে—অবশিষ্ট কাজটিকে কিউ-এর পিছনে না পাঠিয়ে বরং সামনে নিয়ে আসে। এটি আপনাকে উভয় দিকের সেরা সুবিধা দেয়: আপনি আপনার ওয়েবসাইটের ইনপুট রেসপন্সিভনেস উন্নত করতে yield করতে পারেন, এবং একই সাথে এটাও নিশ্চিত করতে পারেন যে yield করার পরে আপনি যে কাজটি শেষ করতে চেয়েছিলেন তা যেন বিলম্বিত না হয়।
চেষ্টা করে দেখুন!
যদি scheduler.yield আপনার কাছে আকর্ষণীয় মনে হয় এবং আপনি এটি ব্যবহার করে দেখতে চান, তবে Chrome-এর ১১৫ নম্বর সংস্করণ থেকে আপনি দুটি উপায়ে তা করতে পারেন:
- আপনি যদি স্থানীয়ভাবে
scheduler.yieldনিয়ে পরীক্ষা করতে চান, তাহলে Chrome-এর অ্যাড্রেস বারেchrome://flagsটাইপ করে এন্টার চাপুন এবং Experimental Web Platform Features সেকশনের ড্রপ-ডাউন থেকে Enable নির্বাচন করুন। এর ফলেscheduler.yield(এবং অন্য যেকোনো পরীক্ষামূলক ফিচার) শুধুমাত্র আপনার Chrome-এর ইনস্ট্যান্সেই উপলব্ধ হবে। - আপনি যদি সর্বজনীনভাবে অ্যাক্সেসযোগ্য কোনো অরিজিনে প্রকৃত ক্রোমিয়াম ব্যবহারকারীদের জন্য
scheduler.yieldসক্রিয় করতে চান, তাহলে আপনাকেscheduler.yieldঅরিজিন ট্রায়ালের জন্য সাইন আপ করতে হবে। এটি আপনাকে একটি নির্দিষ্ট সময়ের জন্য প্রস্তাবিত ফিচারগুলো নিয়ে নিরাপদে পরীক্ষা করার সুযোগ দেয় এবং সেই ফিচারগুলো বাস্তবে কীভাবে ব্যবহৃত হচ্ছে, সে সম্পর্কে ক্রোম টিমকে মূল্যবান ধারণা দেয়। অরিজিন ট্রায়াল কীভাবে কাজ করে সে সম্পর্কে আরও তথ্যের জন্য, এই গাইডটি পড়ুন ।
যেসব ব্রাউজার scheduler.yield প্রয়োগ করে না, সেগুলোকে সমর্থন করার পাশাপাশি আপনি কীভাবে এটি ব্যবহার করবেন, তা আপনার লক্ষ্যের উপর নির্ভর করে। আপনি অফিসিয়াল পলিফিলটি ব্যবহার করতে পারেন। যদি নিম্নলিখিত বিষয়গুলো আপনার ক্ষেত্রে প্রযোজ্য হয়, তবে পলিফিলটি কার্যকর হবে:
- আপনি আপনার অ্যাপ্লিকেশনে টাস্ক শিডিউল করার জন্য ইতিমধ্যেই
scheduler.postTaskব্যবহার করছেন। - আপনি কাজ এবং তার ফলাফলের অগ্রাধিকার নির্ধারণ করতে সক্ষম হতে চান।
- আপনি
scheduler.postTaskAPI-এরTaskControllerক্লাসটি ব্যবহার করে টাস্ক বাতিল বা অগ্রাধিকার পুনর্বিন্যাস করতে চান।
যদি আপনার পরিস্থিতি এমন না হয়, তাহলে এই পলিফিলটি আপনার জন্য উপযুক্ত নাও হতে পারে। সেক্ষেত্রে, আপনি কয়েকটি উপায়ে নিজের মতো করে একটি ফলব্যাক তৈরি করে নিতে পারেন। প্রথম পদ্ধতিটিতে, scheduler.yield উপলব্ধ থাকলে সেটি ব্যবহার করা হয়, কিন্তু উপলব্ধ না থাকলে setTimeout এ ফিরে যাওয়া হয়:
// A function for shimming scheduler.yield and setTimeout:
function yieldToMain () {
// Use scheduler.yield if it exists:
if ('scheduler' in window && 'yield' in scheduler) {
return scheduler.yield();
}
// Fall back to setTimeout:
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
// Example usage:
async function doWork () {
// Do some work:
// ...
await yieldToMain();
// Do some other work:
// ...
}
এটা কাজ করতে পারে, কিন্তু আপনি যেমনটা অনুমান করতে পারেন, যে ব্রাউজারগুলো scheduler.yield সমর্থন করে না, সেগুলো "ফ্রন্ট অফ কিউ" আচরণ ছাড়াই yield করবে। এর মানে যদি এই হয় যে আপনি একেবারেই yield করতে চান না, তাহলে আপনি অন্য একটি পদ্ধতি চেষ্টা করতে পারেন যা scheduler.yield উপলব্ধ থাকলে তা ব্যবহার করে, কিন্তু উপলব্ধ না থাকলে একেবারেই yield করে না:
// A function for shimming scheduler.yield with no fallback:
function yieldToMain () {
// Use scheduler.yield if it exists:
if ('scheduler' in window && 'yield' in scheduler) {
return scheduler.yield();
}
// Fall back to nothing:
return;
}
// Example usage:
async function doWork () {
// Do some work:
// ...
await yieldToMain();
// Do some other work:
// ...
}
scheduler.yield হলো scheduler API-এর একটি চমৎকার সংযোজন—যা আশা করা যায়, ডেভেলপারদের জন্য বর্তমান ইয়েল্ডিং কৌশলগুলোর চেয়ে রেসপন্সিভনেস উন্নত করা আরও সহজ করে তুলবে। যদি scheduler.yield আপনার কাছে একটি দরকারি API বলে মনে হয়, তবে এটিকে আরও উন্নত করতে আমাদের গবেষণায় অংশগ্রহণ করুন এবং কীভাবে এটিকে আরও উন্নত করা যায় সে বিষয়ে মতামত দিন ।
আনস্প্ল্যাশ থেকে নেওয়া প্রধান ছবিটি জোনাথন অ্যালিসনের তোলা।