দক্ষ ব্যাকগ্রাউন্ড প্রসেসিং

ওয়েব ফিচার: content-visibility

সিস্টেম রিসোর্স ও ব্যাটারির আয়ু বাঁচাতে, ব্রাউজার কোনও কম্পোনেন্ট রেন্ডার না করলে, ব্যাকগ্রাউন্ডে চলা ভারী টাস্ক পজ করুন।

এক নজরে

content-visibility: auto প্রপার্টি ব্রাউজারকে ভিউপোর্টের অনেক বাইরে থাকা এলিমেন্টের জন্য রেন্ডারিং ক্যালকুলেশন এড়িয়ে যেতে দেয়। ব্রাউজার যখন কোনও এলিমেন্টের জন্য রেন্ডারিং এড়িয়ে যাওয়ার বা আবার শুরু করার সিদ্ধান্ত নেয়, তখন এটি সেই এলিমেন্টে contentvisibilityautostatechange ইভেন্ট ফায়ার করে।

এই ইভেন্ট শোনার মাধ্যমে, আপনি <canvas> অ্যানিমেশন, WebGL রেন্ডারিং বা হাই-ফ্রিকোয়েন্সি WebSocket ডেটা পোলিংয়ের মতো ব্যয়বহুল অপারেশনগুলি যখন প্রয়োজন হয় না তখন পজ করতে পারেন এবং ব্রাউজার কন্টেন্ট দেখানোর জন্য প্রস্তুত হলে ঠিক সময়ে সেগুলি আবার শুরু করতে পারেন।

contentvisibilityautostatechange বনাম IntersectionObserver

কোন API কখন ব্যবহার করতে হবে তা বোঝা গুরুত্বপূর্ণ:

  • ভিউ পোর্টে কোনও এলিমেন্টের সঠিক ভিজ্যুয়াল দৃশ্যমানতার সাথে যুক্ত IntersectionObserver অ্যাপ্লিকেশন লজিকের জন্য ব্যবহার করুন (যেমন, ধীরে ধীরে লোড হওয়া ডেটা, অসীম স্ক্রল ট্রিগার)।
  • রেন্ডারিং-হেভি কাজের জন্য contentvisibilityautostatechange ব্যবহার করুন (যেমন জটিল ক্যানভাস আপডেট বা হেভি DOM মিউটেশন)। এই ইভেন্টটি সরাসরি ব্রাউজারের ইন্টার্নাল রেন্ডারিং লাইফসাইকেলের সাথে যুক্ত। ব্রাউজার প্রায়ই কোনও এলিমেন্ট স্ক্রিনে দেখানোর আগে সেটি রেন্ডার করা শুরু করে দেয় (প্রি-রেন্ডার মার্জিন)। এই ইভেন্ট আপনাকে জানায় যে কখন এটি হয়, যাতে আপনার কন্টেন্ট দেখার জন্য রেডি থাকে।

প্রয়োগ

১. CSS কন্টেন্ট ভিজিবিলিটি প্রয়োগ করুন

স্ক্রলবার জাম্পিং প্রতিরোধ করতে ভারী কন্টেনারে content-visibility: auto সেট করুন এবং একটি প্লেসহোল্ডার সাইজ প্রদান করুন।

.heavy-component {
  /* Defer rendering work when off-screen */
  content-visibility: auto;
  
  /* Mandatory: Provide a placeholder size to prevent layouts shifts.
    - 'auto' is optional and enables the browser to remember the actual size
      once rendered. It must be paired with a <length> value to be used for
      the first render.
    - 'none' tells the browser not to apply any intrinsic width to this element.
      It can be used for either the height or the width value.
    - '500px' is the estimated height of this element. This can be any valid
      CSS <length> value. Replace it with the expected height of your
      component.
   */
  contain-intrinsic-size: auto none auto 500px;
}

২. স্ট্যাটাস পরিবর্তনের জন্য শুনুন

ব্যাকগ্রাউন্ড টাস্ক পজ বা আবার চালু করতে contentvisibilityautostatechange-এর জন্য ইভেন্ট লিসেনার যোগ করুন।

const component = document.querySelector('.heavy-component');

// Option 1: Direct listener (recommended)
component.addEventListener('contentvisibilityautostatechange', (event) => {
  if (event.skipped) {
    // The browser skipped rendering this content.
    // DO NOT perform heavy mutations or animation loops here.
    stopSimulation();
    pauseWebSocketPolling();
  } else {
    // The browser is about to render the content.
    // Resume your work so it is ready when visible.
    startSimulation();
    resumeWebSocketPolling();
  }
});

// Option 2: Capturing listener for event delegation
document.addEventListener('contentvisibilityautostatechange', (event) => {
  if (event.target.matches('.heavy-component')) {
    if (event.skipped) {
      stopSimulation();
    } else {
      startSimulation();
    }
  }
}, { capture: true });

ফলব্যাক স্ট্র্যাটেজি

content-visibility প্রপার্টি এবং সংশ্লিষ্ট contentvisibilityautostatechange ইভেন্ট হল প্রোগ্রেসিভ এনহ্যান্সমেন্ট। যেসব ব্রাউজারে এগুলি কাজ করে না:

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

পুরনো ব্রাউজারে টাস্ক পজ করার সুবিধা দিতেই হলে, আপনি আনুমানিক সময় হিসেবে IntersectionObserver ব্যবহার করতে পারেন। এটি পুরনো ডিভাইসেও ব্যাটারি ও সিপিইউ বাঁচাতে সাহায্য করে।

// Fallback using IntersectionObserver for older browsers
const target = document.getElementById('target-container');

// Check if content-visibility is supported
const isSupported = 'contentVisibility' in document.documentElement.style;

if (!isSupported) {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        // The element is close to the screen. Start work!
        startSimulation();
      } else {
        // The element is far away. Pause work!
        stopSimulation();
      }
    });
  }, {
    // Use rootMargin to start rendering before it hits the screen
    rootMargin: '200px'
  });

  observer.observe(target);
}