বড় টাস্ক অপ্টিমাইজ করুন

আপনাকে "মূল থ্রেড ব্লক করবেন না" এবং "আপনার বড় টাস্কগুলি ভেঙে দিন" বলা হয়েছে, কিন্তু সেই কাজগুলি করার অর্থ কী?

প্রকাশিত: ৩০ সেপ্টেম্বর, ২০২২, শেষবার আপডেট করা হয়েছে: ১৯ ডিসেম্বর, ২০২৪

JavaScript অ্যাপ দ্রুত রাখার জন্য সাধারণ পরামর্শগুলি নিম্নলিখিত পরামর্শে সংক্ষিপ্ত করা যেতে পারে:

  • "প্রধান থ্রেড ব্লক করবেন না।"
  • "আপনার বড় টাস্কগুলি ছোট ছোট টাস্কে ভাগ করুন।"

এটি খুব ভালো পরামর্শ, তবে এর জন্য কী কী কাজ করতে হবে? কম JavaScript শিপ করা ভালো, কিন্তু এটি কি অটোমেটিক আরও বেশি রেসপন্সিভ ইউজার ইন্টারফেসের সমতুল্য? হতে পারে, আবার নাও হতে পারে।

JavaScript-এ টাস্ক কীভাবে অপ্টিমাইজ করতে হয় তা বুঝতে, প্রথমে আপনাকে জানতে হবে টাস্ক কী এবং ব্রাউজার কীভাবে সেগুলি ম্যানেজ করে।

টাস্ক কী?

টাস্ক হল ব্রাউজারের করা যেকোনও বিচ্ছিন্ন কাজ। এই কাজের মধ্যে রয়েছে রেন্ডারিং, HTML ও CSS পার্স করা, জাভাস্ক্রিপ্ট চালানো এবং অন্যান্য ধরনের কাজ যার উপর আপনার সরাসরি নিয়ন্ত্রণ নাও থাকতে পারে। এই সবকিছুর মধ্যে, আপনার লেখা জাভাস্ক্রিপ্ট সম্ভবত টাস্কের সবচেয়ে বড় সোর্স।

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

জাভাস্ক্রিপ্টের সাথে যুক্ত টাস্ক দু'টি উপায়ে পারফর্ম্যান্সকে প্রভাবিত করে:

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

ওয়েব ওয়ার্কার এবং একই ধরনের API ছাড়া এই সব কাজ মূল থ্রেডে হয়।

মূল থ্রেড কী?

প্রধান থ্রেড হল সেই জায়গা যেখানে ব্রাউজারে বেশিরভাগ টাস্ক রান করে এবং যেখানে আপনার লেখা প্রায় সব জাভাস্ক্রিপ্ট এক্সিকিউট করা হয়।

মূল থ্রেড একবারে শুধুমাত্র একটি টাস্ক প্রসেস করতে পারে। ৫০ মিলিসেকেন্ডের বেশি সময় লাগে এমন যেকোনও টাস্ক হল বড় টাস্ক। ৫০ মিলিসেকেন্ডের বেশি সময় ধরে চলা টাস্কের ক্ষেত্রে, টাস্কের মোট সময় থেকে ৫০ মিলিসেকেন্ড বাদ দিলে যে সময় পাওয়া যায় তাকে টাস্কের ব্লকিং পিরিয়ড বলা হয়।

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

Chrome-এর DevTools-এর পারফর্ম্যান্স প্রোফাইলারের একটি বড় টাস্ক। টাস্কের যে অংশটি ব্লক করা হয়েছে (৫০ মিলিসেকেন্ডের বেশি) সেটি লাল রঙের কোণাকুণি স্ট্রাইপের প্যাটার্ন দিয়ে দেখানো হয়েছে।
Chrome-এর পারফর্ম্যান্স প্রোফাইলারের দেখানো বড় টাস্ক। টাস্কের কোণে লাল ত্রিভুজ দিয়ে বড় টাস্ক চিহ্নিত করা হয় এবং টাস্কের যে অংশ ব্লক করা আছে সেটি লাল রঙের কোণাকুণি স্ট্রাইপ দিয়ে ভর্তি করা থাকে।

অনেকক্ষণ ধরে মূল থ্রেড ব্লক হওয়া আটকাতে, আপনি একটি বড় টাস্ককে একাধিক ছোট টাস্কে ভাগ করতে পারেন।

একটি বড় টাস্ক বনাম একই টাস্ক ছোট ছোট টাস্কে ভাগ করা। বড় টাস্ক হল একটি বড় আয়তক্ষেত্র, যেখানে খণ্ডিত টাস্ক হল পাঁচটি ছোট বক্স যা সম্মিলিতভাবে বড় টাস্কের সমান প্রস্থের।
একটি বড় টাস্কের ভিজ্যুয়ালাইজেশন বনাম একই টাস্ক পাঁচটি ছোট টাস্কে বিভক্ত।

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

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

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

টাস্ক ভেঙে নেওয়া কেন গুরুত্বপূর্ণ তা আপনি এখন জানেন, তাই জাভাস্ক্রিপ্টে কীভাবে এটি করবেন তা শিখতে পারেন।

টাস্ক ম্যানেজমেন্ট স্ট্র্যাটেজি

সফ্টওয়্যার আর্কিটেকচারে একটি সাধারণ পরামর্শ হল আপনার কাজকে ছোট ছোট ফাংশনে ভাগ করা:

function saveSettings () {
  validateForm();
  showSpinner();
  saveToDatabase();
  updateUI();
  sendAnalytics();
}

এই উদাহরণে, saveSettings() নামের একটি ফাংশন আছে যা ফর্ম যাচাই, স্পিনার দেখানো, অ্যাপ্লিকেশন ব্যাকএন্ডে ডেটা পাঠানো, ইউজার ইন্টারফেস আপডেট করা এবং অ্যানালিটিক্স পাঠানোর জন্য পাঁচটি ফাংশনকে কল করে।

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

তবে, এখানে একটি সম্ভাব্য সমস্যা হল, জাভাস্ক্রিপ্ট এই প্রতিটি ফাংশনকে আলাদা টাস্ক হিসেবে রান করে না, কারণ সেগুলি saveSettings() ফাংশনের মধ্যে এক্সিকিউট করা হয়। এর অর্থ হল, পাঁচটি ফাংশনই একটি টাস্ক হিসেবে রান করবে।

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

সবচেয়ে ভালো পরিস্থিতিতে, এই ফাংশনগুলির মধ্যে একটিও টাস্কের মোট দৈর্ঘ্যে ৫০ মিলিসেকেন্ড বা তার বেশি অবদান রাখতে পারে। সবচেয়ে খারাপ পরিস্থিতিতে, এইসব টাস্কের মধ্যে অনেকগুলি অনেক বেশি সময় ধরে চলতে পারে—বিশেষ করে রিসোর্স-সীমাবদ্ধ ডিভাইসে।

এই ক্ষেত্রে, ব্যবহারকারীর ক্লিকের মাধ্যমে saveSettings() ট্রিগার করা হয় এবং সম্পূর্ণ ফাংশনটি রান করা শেষ না হওয়া পর্যন্ত ব্রাউজার কোনও রেসপন্স দেখাতে পারে না বলে, এই বড় টাস্কের ফলাফল হল একটি ধীর এবং রেসপন্স না করা UI এবং এটি একটি খারাপ ইন্টার‍্যাকশন টু নেক্সট পেন্ট (INP) হিসেবে পরিমাপ করা হবে।

ম্যানুয়ালি কোড এক্সিকিউশন স্থগিত করা

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

টাস্ককে ছোট ছোট ভাগে ভাগ করার জন্য ডেভেলপাররা যে পদ্ধতি ব্যবহার করেছেন তার মধ্যে একটি হল setTimeout()। এই টেকনিকের মাধ্যমে, আপনি setTimeout()-এ ফাংশন পাস করেন। আপনি 0-এর টাইমআউট নির্দিষ্ট করলেও, এটি আলাদা টাস্কে কলব্যাক এক্সিকিউশন স্থগিত করে।

function saveSettings () {
  // Do critical work that is user-visible:
  validateForm();
  showSpinner();
  updateUI();

  // Defer work that isn't user-visible to a separate task:
  setTimeout(() => {
    saveToDatabase();
    sendAnalytics();
  }, 0);
}

এটি ইল্ডিং নামে পরিচিত এবং এটি এমন একগুচ্ছ ফাংশনের জন্য সবচেয়ে ভাল কাজ করে যেগুলি ক্রমানুসারে চালানো প্রয়োজন।

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

function processData () {
  for (const item of largeDataArray) {
    // Process the individual item here.
  }
}

ডেভেলপার এর্গোনমিক্সের কারণে এখানে setTimeout() ব্যবহার করা সমস্যাজনক এবং নেস্ট করা setTimeout()-এর পাঁচটি রাউন্ডের পরে, ব্রাউজার প্রতিটি অতিরিক্ত setTimeout()-এর জন্য ন্যূনতম ৫ মিলিসেকেন্ড বিলম্ব আরোপ করা শুরু করবে।

ইল্ডিংয়ের ক্ষেত্রে setTimeout-এর আরেকটি ত্রুটি আছে: setTimeout ব্যবহার করে পরবর্তী টাস্কে রান করার জন্য কোড ডিফার করে আপনি যখন মেইন থ্রেডে ইল্ড করেন, তখন সেই টাস্কটি সারির শেষে যোগ করা হয়। অন্য কোনও টাস্ক বাকি থাকলে, আপনার স্থগিত করা কোডের আগে সেগুলি রান করবে।

একটি ডেডিকেটেড ইল্ডিং API: scheduler.yield()

Browser Support

  • Chrome: 129.
  • Edge: 129.
  • Firefox: 142.
  • Safari: not supported.

Source

scheduler.yield() হল একটি API যা বিশেষভাবে ব্রাউজারের প্রধান থ্রেডে ইল্ড করার জন্য ডিজাইন করা হয়েছে।

এটি ভাষা-লেভেল সিনট্যাক্স বা বিশেষ কনস্ট্রাক্ট নয়; scheduler.yield() হল এমন একটি ফাংশন যা Promise রিটার্ন করে এবং এটি ভবিষ্যতের টাস্কে সমাধান করা হবে। Promise সমাধান হওয়ার পরে (স্পষ্ট .then() চেনে অথবা অ্যাসিঙ্ক ফাংশনে await করার পরে) রান করার জন্য চেনে থাকা যেকোনও কোড, সেই ফিউচার টাস্কে রান করবে।

ব্যবহারিক ক্ষেত্রে: একটি await scheduler.yield() যোগ করুন এবং ফাংশনটি সেই পয়েন্টে এক্সিকিউশন পজ করবে এবং মূল থ্রেডে ফিরে যাবে। ফাংশনের বাকি অংশ এক্সিকিউট করা—যাকে ফাংশনের কন্টিনিউয়েশন বলা হয়—নতুন ইভেন্ট-লুপ টাস্কে রান করার জন্য শিডিউল করা হবে। সেই টাস্ক শুরু হলে, প্রতীক্ষিত প্রমিস সমাধান করা হবে এবং ফাংশনটি যেখানে বন্ধ করা হয়েছিল সেখান থেকে আবার শুরু হবে।

async function saveSettings () {
  // Do critical work that is user-visible:
  validateForm();
  showSpinner();
  updateUI();

  // Yield to the main thread:
  await scheduler.yield()

  // Work that isn't user-visible, continued in a separate task:
  saveToDatabase();
  sendAnalytics();
}
Chrome-এর পারফর্ম্যান্স প্রোফাইলারের মধ্যে saveSettings ফাংশনটি এখন দুটি টাস্কে বিভক্ত। প্রথম টাস্ক দুটি ফাংশন কল করে, তারপর ইল্ড করে, যার ফলে লেআউট এবং পেইন্ট কাজ করতে পারে এবং ব্যবহারকারীকে একটি দৃশ্যমান প্রতিক্রিয়া দেয়। এর ফলে, ক্লিক ইভেন্টটি অনেক দ্রুত, মাত্র ৬৪ মিলিসেকেন্ডে শেষ হয়। দ্বিতীয় টাস্কটি শেষ তিনটি ফাংশনকে কল করে।
saveSettings() ফাংশনটি এখন দুটি টাস্কে ভাগ করে এক্সিকিউট করা হয়েছে। এর ফলে, টাস্কের মধ্যে লেআউট ও পেইন্ট রান করতে পারে, যা ব্যবহারকারীকে আরও দ্রুত ভিজ্যুয়াল রেসপন্স দেয়, যা এখন অনেক ছোট পয়েন্টার ইন্টার‍্যাকশন দ্বারা পরিমাপ করা হয়।

তবে, অন্যান্য ইল্ডিং পদ্ধতির তুলনায় scheduler.yield()-এর আসল সুবিধা হল, এটি চালিয়ে যাওয়ার উপর অগ্রাধিকার দেওয়া হয়, যার অর্থ হল, আপনি কোনও টাস্কের মাঝখানে ইল্ড করলে, অন্য কোনও একই ধরনের টাস্ক শুরু হওয়ার আগে বর্তমান টাস্কটি চালিয়ে যাওয়া হবে।

এটি অন্যান্য টাস্ক সোর্স থেকে আসা কোডকে আপনার কোড এক্সিকিউশনের ক্রমকে বাধা দিতে বাধা দেয়, যেমন থার্ড-পার্টি স্ক্রিপ্ট থেকে আসা টাস্ক।

তিনটি ডায়াগ্রামের মাধ্যমে ইল্ডিং ছাড়া, ইল্ডিং সহ এবং ইল্ডিং ও কন্টিনিউয়েশন সহ টাস্ক দেখানো হয়েছে। ইল্ডিং না থাকলে, বড় টাস্ক থাকে। ইল্ডিংয়ের ক্ষেত্রে, আরও বেশি সংখ্যক ছোট ছোট টাস্ক থাকে, তবে অন্যান্য সম্পর্কহীন টাস্কের কারণে সেগুলি বাধাগ্রস্ত হতে পারে। ইল্ডিং ও কন্টিনিউয়েশনের মাধ্যমে, আরও বেশি টাস্ক থাকে যেগুলি ছোট, তবে সেগুলি কার্যকর করার ক্রম বজায় রাখা হয়।
আপনি scheduler.yield() ব্যবহার করলে, অন্যান্য টাস্কে যাওয়ার আগে যেখানে শেষ করেছিলেন সেখান থেকে শুরু হয়।

ক্রস-ব্রাউজার সহায়তা

scheduler.yield() এখনও সব ব্রাউজারে কাজ করে না, তাই একটি ফলব্যাক প্রয়োজন।

একটি সমাধান হল আপনার বিল্ডে scheduler-polyfill ড্রপ করা এবং তারপর scheduler.yield() সরাসরি ব্যবহার করা যেতে পারে; পলিফিল অন্যান্য টাস্ক-শিডিউলিং ফাংশনে ফিরে আসার বিষয়টি ম্যানেজ করবে যাতে এটি সব ব্রাউজার জুড়ে একইভাবে কাজ করে।

বিকল্প হিসেবে, scheduler.yield() উপলভ্য না থাকলে, ফলব্যাক হিসেবে Promise-এ র‍্যাপ করা শুধু setTimeout ব্যবহার করে, কয়েক লাইনে একটি কম জটিল ভার্সন লেখা যেতে পারে।

function yieldToMain () {
  if (globalThis.scheduler?.yield) {
    return scheduler.yield();
  }

  // Fall back to yielding with setTimeout.
  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
}

scheduler.yield() সাপোর্ট করে না এমন ব্রাউজার প্রায়োরিটি কন্টিনিউয়েশন না পেলেও, ব্রাউজার যাতে রেসপন্সিভ থাকে তার জন্য সেগুলি ইল্ড করবে।

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

এটি ফিচার শনাক্তকরণ এবং একটি সুবিধাজনক ওয়ান-লাইনারে একটি মাইক্রোটাস্কের জন্য অপেক্ষা করার মাধ্যমে করা যেতে পারে:

// Yield to the main thread if scheduler.yield() is available.
await globalThis.scheduler?.yield?.();

scheduler.yield()-এর সাহায্যে দীর্ঘ সময় ধরে চলা কাজকে ছোট ছোট ভাগে ভাগ করুন

scheduler.yield() ব্যবহার করার এইসব পদ্ধতির যেকোনও একটি ব্যবহার করার সুবিধা হল যে আপনি যেকোনও async ফাংশনে এটি await করতে পারবেন।

যেমন, আপনার কাছে যদি রান করার জন্য অনেক কাজ থাকে যা প্রায়শই একটি বড় টাস্কের সাথে যোগ হয়, তাহলে আপনি টাস্কটি ভেঙে দেওয়ার জন্য ইল্ড যোগ করতে পারেন।

async function runJobs(jobQueue) {
  for (const job of jobQueue) {
    // Run the job:
    job();

    // Yield to the main thread:
    await yieldToMain();
  }
}

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

তবে, এটি ইল্ডিংয়ের দক্ষ ব্যবহার নয়। scheduler.yield() দ্রুত ও দক্ষ, তবে এতে কিছু ওভারহেড আছে। jobQueue-এর কিছু কাজ খুব ছোট হলে, প্রকৃত কাজ কার্যকর করার চেয়ে ফলন এবং পুনরায় শুরু করার জন্য ব্যয় করা অতিরিক্ত সময় দ্রুত যোগ হতে পারে।

একটি পদ্ধতি হল, জব ব্যাচ করা, শেষবার ইল্ড করার পর থেকে যথেষ্ট সময় অতিবাহিত হলে তবেই তাদের মধ্যে ইল্ড করা। টাস্ক যাতে বড় টাস্ক না হয়ে যায় তার জন্য সাধারণত ৫০ মিলিসেকেন্ডের ডেডলাইন সেট করা হয়, তবে রেসপন্সিভনেস ও জব কিউ সম্পূর্ণ করার সময়ের মধ্যে ট্রেড-অফ হিসেবে এটি অ্যাডজাস্ট করা যেতে পারে।

async function runJobs(jobQueue, deadline=50) {
  let lastYield = performance.now();

  for (const job of jobQueue) {
    // Run the job:
    job();

    // If it's been longer than the deadline, yield to the main thread:
    if (performance.now() - lastYield > deadline) {
      await yieldToMain();
      lastYield = performance.now();
    }
  }
}

এর ফলে, কাজগুলি এমনভাবে ভাগ করা হয় যাতে সেগুলি রান করতে খুব বেশি সময় না লাগে, তবে রানার প্রতি ৫০ মিলিসেকেন্ডে একবার মূল থ্রেডে ফিরে আসে।

Chrome DevTools পারফর্ম্যান্স প্যানেলে দেখানো জব ফাংশনের সিরিজ, যার এক্সিকিউশন একাধিক টাস্কে বিভক্ত
একাধিক টাস্কে ব্যাচ করা কাজ।

isInputPending() ব্যবহার করবেন না

Browser Support

  • Chrome: 87.
  • Edge: 87.
  • Firefox: not supported.
  • Safari: not supported.

Source

isInputPending() API ব্যবহারকারী কোনও পৃষ্ঠার সাথে ইন্টার‍্যাক্ট করার চেষ্টা করেছেন কিনা তা চেক করার একটি উপায় প্রদান করে এবং কোনও ইনপুট বাকি থাকলে তবেই তা দেখায়।

এর ফলে, কোনও ইনপুট বাকি না থাকলে, জাভাস্ক্রিপ্ট টাস্ক কিউয়ের শেষে না গিয়ে কাজ চালিয়ে যেতে পারে। এর ফলে পারফর্ম্যান্সের ক্ষেত্রে উল্লেখযোগ্য উন্নতি হতে পারে, যেমন Intent to Ship-এ বিস্তারিতভাবে উল্লেখ করা হয়েছে, এমন সাইটের ক্ষেত্রে যা অন্যথায় মূল থ্রেডে ফিরে নাও আসতে পারে।

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

  • কিছু পরিস্থিতিতে ব্যবহারকারী ইন্টার‍্যাক্ট করলেও isInputPending() ভুল করে false দেখাতে পারে।
  • ইনপুটই একমাত্র কেস নয় যেখানে টাস্কের ফলাফল পাওয়া যায়। রেসপন্সিভ ওয়েব পেজ প্রদান করার জন্য অ্যানিমেশন ও অন্যান্য নিয়মিত ইউজার ইন্টারফেস আপডেট সমানভাবে গুরুত্বপূর্ণ হতে পারে।
  • আরও ব্যাপক ইল্ডিং API চালু করা হয়েছে যা ইল্ডিং সংক্রান্ত সমস্যা সমাধান করে, যেমন scheduler.postTask() এবং scheduler.yield()।

উপসংহার

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

  • গুরুত্বপূর্ণ, ব্যবহারকারী নিজে ইন্টার‌্যাক্ট করতে পারেন এমন টাস্কের জন্য প্রধান থ্রেডে ইয়েল্ড করুন।
  • scheduler.yield() (ক্রস-ব্রাউজার ফলব্যাক সহ) ব্যবহার করে এরগোনমিকভাবে ফলন এবং অগ্রাধিকারপ্রাপ্ত ধারাবাহিকতা পান
  • সবশেষে, আপনার ফাংশনে যতটা সম্ভব কম কাজ করুন।

scheduler.yield(), এর এক্সপ্লিসিট টাস্ক-শিডিউলিং রিলেটিভ scheduler.postTask() এবং টাস্কের অগ্রাধিকার সম্পর্কে আরও জানতে, অগ্রাধিকার দেওয়া টাস্ক শিডিউলিং API ডকুমেন্ট দেখুন।

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

এই নির্দেশিকা টেকনিক্যাল দিক থেকে যাচাই করার জন্য ফিলিপ ওয়ালটনকে বিশেষ ধন্যবাদ।