দীর্ঘ কাজ অপ্টিমাইজ করুন

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

জেরেমি ওয়াগনার
জেরেমি ওয়াগনার

আপনি যদি ওয়েব পারফরম্যান্স সম্পর্কে প্রচুর স্টাফ পড়েন, তাহলে আপনার জাভাস্ক্রিপ্ট অ্যাপগুলিকে দ্রুত রাখার জন্য পরামর্শের মধ্যে এই টিডবিটগুলির মধ্যে কিছু জড়িত থাকে:

  • "প্রধান থ্রেড ব্লক করবেন না।"
  • "আপনার দীর্ঘ কাজগুলি ভেঙে দিন।"

যে কোন মানে কি? কম জাভাস্ক্রিপ্ট শিপিং ভাল, কিন্তু এটি কি স্বয়ংক্রিয়ভাবে পৃষ্ঠার জীবনচক্র জুড়ে স্ন্যাপিয়ার ইউজার ইন্টারফেসের সমান? হতে পারে, কিন্তু হয়তো না।

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

একটি টাস্ক কি?

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

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

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

মূল থ্রেড কি?

প্রধান থ্রেড যেখানে বেশিরভাগ কাজ ব্রাউজারে চালানো হয়। এটিকে একটি কারণে প্রধান থ্রেড বলা হয়: এটি এমন একটি থ্রেড যেখানে আপনার লেখা প্রায় সমস্ত জাভাস্ক্রিপ্ট তার কাজ করে।

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

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

আপনাকে কাজগুলি ভাঙতে হবে। এর অর্থ হল একটি দীর্ঘ টাস্ক নেওয়া এবং এটিকে ছোট ছোট কাজগুলিতে ভাগ করা যা পৃথকভাবে চালানোর জন্য কম সময় নেয়।

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

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

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

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

সমস্যা, যদিও, "আপনার দীর্ঘ কাজগুলি ভেঙে দিন" এবং "প্রধান থ্রেডটি ব্লক করবেন না" পরামর্শটি যথেষ্ট নির্দিষ্ট নয় যদি না আপনি ইতিমধ্যে এই জিনিসগুলি কীভাবে করবেন তা জানেন না। যে এই নির্দেশিকা ব্যাখ্যা করবে কি.

টাস্ক ম্যানেজমেন্ট কৌশল

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

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

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

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

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

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

ম্যানুয়ালি কোড এক্সিকিউশন পিছিয়ে দিন

একটি পদ্ধতি ডেভেলপাররা কাজগুলিকে ছোট করে ভাগ করার জন্য ব্যবহার করেছেন 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() ব্যবহার করা সমস্যাযুক্ত, কারণ এটির ergonomics এটি বাস্তবায়ন করা কঠিন করে তোলে, এবং প্রতিটি আইটেম খুব দ্রুত প্রক্রিয়া করা গেলেও ডেটার সম্পূর্ণ বিন্যাস প্রক্রিয়া করতে খুব দীর্ঘ সময় লাগতে পারে। এটি সব যোগ করে, এবং setTimeout() কাজের জন্য সঠিক টুল নয়-অন্তত এইভাবে ব্যবহার করার সময় নয়।

setTimeout() ছাড়াও, আরও কয়েকটি এপিআই রয়েছে যা আপনাকে পরবর্তী কাজের জন্য কোড এক্সিকিউশন স্থগিত করতে দেয়। দ্রুত সময়ের জন্য postMessage() ব্যবহার করা জড়িত । আপনি requestIdleCallback() ব্যবহার করেও কাজ ভাঙতে পারেন —কিন্তু সাবধান!— requestIdleCallback() কাজগুলিকে সর্বনিম্ন সম্ভাব্য অগ্রাধিকারে এবং শুধুমাত্র ব্রাউজার নিষ্ক্রিয় সময়ে সময়সূচী করে৷ যখন মূল থ্রেডটি কনজেস্টেড থাকে, তখন requestIdleCallback() এর সাথে নির্ধারিত কাজগুলি কখনই চলতে পারে না।

ফলন পয়েন্ট তৈরি করতে async / await ব্যবহার করুন

এই গাইডের বাকি অংশ জুড়ে আপনি দেখতে পাবেন একটি বাক্যাংশ হল "মূল থ্রেডের ফলন"—কিন্তু এর অর্থ কী? কেন আপনি এটা করতে হবে? আপনি এটা কখন করা উচিত?

যখন কাজগুলি বিভক্ত হয়, তখন ব্রাউজারের অভ্যন্তরীণ অগ্রাধিকার স্কিম দ্বারা অন্যান্য কাজগুলিকে আরও ভালভাবে অগ্রাধিকার দেওয়া যেতে পারে। মূল থ্রেডে প্রাপ্তির একটি উপায় হল একটি Promise সংমিশ্রণ ব্যবহার করা যা setTimeout() এ কল দিয়ে সমাধান করে :

function yieldToMain () {
  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
}

saveSettings() ফাংশনে, আপনি যদি প্রতিটি ফাংশন কলের পরে yieldToMain() ফাংশনের জন্য await তবে প্রতিটি কাজের পরে আপনি মূল থ্রেডে যোগ দিতে পারেন:

async function saveSettings () {
  // Create an array of functions to run:
  const tasks = [
    validateForm,
    showSpinner,
    saveToDatabase,
    updateUI,
    sendAnalytics
  ]

  // Loop over the tasks:
  while (tasks.length > 0) {
    // Shift the first task off the tasks array:
    const task = tasks.shift();

    // Run the task:
    task();

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

ফলাফল হল যে একসময়ের একচেটিয়া কাজ এখন আলাদা আলাদা কাজে বিভক্ত হয়ে গেছে।

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

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

প্রয়োজন হলেই ফলন

আপনার যদি একগুচ্ছ কাজ থাকে, তবে ব্যবহারকারী যদি পৃষ্ঠাটির সাথে ইন্টারঅ্যাক্ট করার চেষ্টা করে তবেই আপনি ফল পেতে চান? যে ধরনের জিনিস যা isInputPending() তৈরি করা হয়েছিল।

isInputPending() একটি ফাংশন যা আপনি যেকোন সময় চালাতে পারেন তা নির্ধারণ করতে ব্যবহারকারী একটি পৃষ্ঠা উপাদানের সাথে ইন্টারঅ্যাক্ট করার চেষ্টা করছে কিনা: isInputPending() এ একটি কল true ফিরে আসবে। এটি অন্যথায় false ফেরত দেয়।

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

async function saveSettings () {
  // A task queue of functions
  const tasks = [
    validateForm,
    showSpinner,
    saveToDatabase,
    updateUI,
    sendAnalytics
  ];
  
  while (tasks.length > 0) {
    // Yield to a pending user input:
    if (navigator.scheduling.isInputPending()) {
      // There's a pending user input. Yield here:
      await yieldToMain();
    } else {
      // Shift the task out of the queue:
      const task = tasks.shift();

      // Run the task:
      task();
    }
  }
}

saveSettings() রান করার সময়, এটি সারিতে থাকা কাজগুলিকে লুপ করবে। যদি লুপের সময় isInputPending() true , saveSettings() yieldToMain() কল করবে যাতে ব্যবহারকারীর ইনপুট পরিচালনা করা যায়। অন্যথায়, এটি পরবর্তী কাজটিকে সারির সামনে থেকে সরিয়ে দেবে এবং এটি ক্রমাগত চালাবে। আর কোন কাজ বাকি না হওয়া পর্যন্ত এটি এটি করবে।

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

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

ব্যবহার করার আরেকটি উপায় isInputPending() —বিশেষ করে আপনি যদি এমন ব্রাউজারগুলির জন্য একটি ফলব্যাক প্রদানের বিষয়ে উদ্বিগ্ন হন যা এটি সমর্থন করে না—তা হল ঐচ্ছিক চেইনিং অপারেটরের সাথে একত্রে একটি সময়-ভিত্তিক পদ্ধতি ব্যবহার করা:

async function saveSettings () {
  // A task queue of functions
  const tasks = [
    validateForm,
    showSpinner,
    saveToDatabase,
    updateUI,
    sendAnalytics
  ];
  
  let deadline = performance.now() + 50;

  while (tasks.length > 0) {
    // Optional chaining operator used here helps to avoid
    // errors in browsers that don't support `isInputPending`:
    if (navigator.scheduling?.isInputPending() || performance.now() >= deadline) {
      // There's a pending user input, or the
      // deadline has been reached. Yield here:
      await yieldToMain();

      // Extend the deadline:
      deadline = performance.now() + 50;

      // Stop the execution of the current loop and
      // move onto the next iteration:
      continue;
    }

    // Shift the task out of the queue:
    const task = tasks.shift();

    // Run the task:
    task();
  }
}

এই পদ্ধতির সাহায্যে, আপনি এমন ব্রাউজারগুলির জন্য একটি ফলব্যাক পাবেন যেগুলি isInputPending() সমর্থন করে না এমন একটি সময়-ভিত্তিক পদ্ধতি ব্যবহার করে যা একটি সময়সীমা ব্যবহার করে (এবং সামঞ্জস্য করে) যাতে কাজটি যেখানে প্রয়োজন সেখানে বিভক্ত হয়ে যায়, ব্যবহারকারীর ইনপুটকে ফলন দিয়েই হোক, অথবা নির্দিষ্ট সময়ে।

বর্তমান API-এ ফাঁক

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

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

সৌভাগ্যবশত, একটি ডেডিকেটেড শিডিউলার API রয়েছে যা বর্তমানে বিকাশে রয়েছে যা এই সমস্যাগুলির সমাধান করে।

একটি ডেডিকেটেড সময়সূচী API

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

postTask() API এর তিনটি অগ্রাধিকার রয়েছে যা আপনি ব্যবহার করতে পারেন:

  • সর্বনিম্ন অগ্রাধিকারমূলক কাজের জন্য 'background'
  • মাঝারি অগ্রাধিকারমূলক কাজের জন্য 'user-visible' । কোন priority সেট না থাকলে এটি ডিফল্ট।
  • 'user-blocking' গুরুত্বপূর্ণ কাজগুলির জন্য যা উচ্চ অগ্রাধিকারে চালানো প্রয়োজন।

একটি উদাহরণ হিসাবে নিম্নলিখিত কোডটি নিন, যেখানে postTask() API সর্বোচ্চ সম্ভাব্য অগ্রাধিকারে তিনটি কাজ চালানোর জন্য এবং বাকি দুটি কাজ সর্বনিম্ন সম্ভাব্য অগ্রাধিকারে চালানোর জন্য ব্যবহৃত হয়।

function saveSettings () {
  // Validate the form at high priority
  scheduler.postTask(validateForm, {priority: 'user-blocking'});

  // Show the spinner at high priority:
  scheduler.postTask(showSpinner, {priority: 'user-blocking'});

  // Update the database in the background:
  scheduler.postTask(saveToDatabase, {priority: 'background'});

  // Update the user interface at high priority:
  scheduler.postTask(updateUI, {priority: 'user-blocking'});

  // Send analytics data in the background:
  scheduler.postTask(sendAnalytics, {priority: 'background'});
};

এখানে, কাজের অগ্রাধিকার এমনভাবে নির্ধারিত হয় যাতে ব্রাউজার-অগ্রাধিকারযুক্ত কাজগুলি-যেমন ব্যবহারকারীর মিথস্ক্রিয়া-তাদের উপায়ে কাজ করতে পারে।

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

postTask() কীভাবে ব্যবহার করা যেতে পারে তার এটি একটি সরল উদাহরণ। বিভিন্ন TaskController অবজেক্টগুলিকে ইনস্ট্যান্ট করা সম্ভব যা প্রয়োজন অনুসারে বিভিন্ন TaskController দৃষ্টান্তগুলির জন্য অগ্রাধিকার পরিবর্তন করার ক্ষমতা সহ কাজের মধ্যে অগ্রাধিকার ভাগ করতে পারে।

scheduler.yield মাধ্যমে ধারাবাহিকতার সাথে অন্তর্নির্মিত ফলন

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

async function saveSettings () {
  // Create an array of functions to run:
  const tasks = [
    validateForm,
    showSpinner,
    saveToDatabase,
    updateUI,
    sendAnalytics
  ]

  // Loop over the tasks:
  while (tasks.length > 0) {
    // Shift the first task off the tasks array:
    const task = tasks.shift();

    // Run the task:
    task();

    // Yield to the main thread with the scheduler
    // API's own yielding mechanism:
    await scheduler.yield();
  }
}

আপনি লক্ষ্য করবেন যে উপরের কোডটি মূলত পরিচিত, কিন্তু yieldToMain() ব্যবহার করার পরিবর্তে, আপনি কল করুন এবং তার পরিবর্তে await scheduler.yield()

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

scheduler.yield() এর সুবিধা হল ধারাবাহিকতা, যার মানে হল যে আপনি যদি একটি সেট কাজের মাঝখানে ফলন করেন, তবে অন্যান্য নির্ধারিত কাজগুলি ফলন পয়েন্টের পরে একই ক্রমে চলতে থাকবে। এটি তৃতীয় পক্ষের স্ক্রিপ্ট থেকে কোডকে আপনার কোডের কার্যকর করার ক্রম দখল থেকে এড়িয়ে যায়।

উপসংহার

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

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

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

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

আমিরালি মিরহাশেমিয়ানের সৌজন্যে নায়কের ছবি আনস্প্ল্যাশ থেকে নেওয়া।