Chrome 88 में, चेन वाले JS टाइमर की भारी थ्रॉटलिंग.

Chrome 88 (जनवरी 2021) में, कुछ खास स्थितियों में छिपे हुए पेजों के लिए, चेन किए गए JavaScript टाइमर को काफ़ी धीमा कर दिया जाएगा. इससे सीपीयू का इस्तेमाल कम होगा. साथ ही, बैटरी का इस्तेमाल भी कम होगा. कुछ मामलों में, इससे व्यवहार में बदलाव होगा. हालांकि, टाइमर का इस्तेमाल अक्सर तब किया जाता है, जब कोई दूसरा एपीआई ज़्यादा बेहतर और भरोसेमंद हो.

ठीक है, यह काफ़ी जटिल और समझ में न आने वाला सवाल था. आइए, जानते हैं…

शब्दावली

छिपे हुए पेज

आम तौर पर, छिपा हुआ का मतलब है कि कोई दूसरा टैब चालू है या विंडो को छोटा कर दिया गया है. हालांकि, जब पेज का कॉन्टेंट पूरी तरह से न दिखे, तब ब्राउज़र उसे छिपा हुआ मान सकते हैं. कुछ ब्राउज़र, अन्य ब्राउज़र की तुलना में ज़्यादा जानकारी देते हैं. हालांकि, जब ब्राउज़र को लगता है कि पेज की विज़िबिलिटी में बदलाव हुआ है, तो ट्रैक करने के लिए पेज विज़िबिलिटी एपीआई का इस्तेमाल कभी भी किया जा सकता है.

JavaScript टाइमर

JavaScript टाइमर से मेरा मतलब setTimeout और setInterval से है. इनकी मदद से, आने वाले समय में किसी भी समय कॉलबैक शेड्यूल किया जा सकता है. टाइमर काम के होते हैं और इन्हें बंद नहीं किया जा रहा है. हालांकि, कभी-कभी इन्हें स्थिति को पोल करने के लिए तब इस्तेमाल किया जाता है, जब कोई इवेंट ज़्यादा बेहतर और सटीक हो.

एक-दूसरे से जुड़े टाइमर

अगर आपने setTimeout को उसी टास्क में setTimeout कॉलबैक के तौर पर कॉल किया है, तो दूसरा कॉल 'चेन किया गया' होता है. setInterval के साथ, हर दोहराव चेन का हिस्सा होता है. कोड की मदद से इसे समझना आसान हो सकता है:

let chainCount = 0;

setInterval(() => {
  chainCount++;
  console.log(`This is number ${chainCount} in the chain`);
}, 500);

और:

let chainCount = 0;

function setTimeoutChain() {
  setTimeout(() => {
    chainCount++;
    console.log(`This is number ${chainCount} in the chain`);
    setTimeoutChain();
  }, 500);
}

थ्रॉटलिंग की सुविधा कैसे काम करती है

थ्रॉटलिंग की प्रोसेस अलग-अलग चरणों में होती है:

कम से कम थ्रॉटलिंग

ऐसा उन टाइमर के लिए होता है जिन्हें शेड्यूल किया जाता है, जब इनमें से कोई भी शर्त पूरी होती है:

  • पेज दिख रहा हो.
  • पिछले 30 सेकंड में पेज पर आवाज़ें आई हैं. यह किसी भी आवाज़ बनाने वाले एपीआई से हो सकता है, लेकिन साइलेंट ऑडियो ट्रैक की गिनती नहीं की जाती.

टाइमर तब तक थ्रॉटल नहीं किया जाता, जब तक कि अनुरोध किया गया टाइम आउट 4 मिलीसेकंड से कम न हो और चैन की संख्या पांच या उससे ज़्यादा न हो. ऐसे में, टाइम आउट को 4 मिलीसेकंड पर सेट किया जाता है. यह तरीका नया नहीं है. ब्राउज़र ऐसा कई सालों से करते आ रहे हैं.

थ्रॉटलिंग

ऐसा उन टाइमर के लिए होता है जिन्हें तब शेड्यूल किया जाता है, जब कम से कम थ्रॉटलिंग लागू नहीं होती और इनमें से कोई भी शर्त पूरी होती है:

  • चेन की संख्या पांच से कम है.
  • पेज को पांच मिनट से भी कम समय के लिए छिपाया गया हो.
  • WebRTC का इस्तेमाल किया जा रहा है. खास तौर पर, RTCPeerConnection में 'ओपन' RTCDataChannel या 'लाइव' MediaStreamTrack है.

ब्राउज़र, इस ग्रुप में मौजूद टाइमर को हर सेकंड में एक बार देखेगा. हर सेकंड में सिर्फ़ एक बार जांच की जाती है. इसलिए, एक जैसे टाइम आउट वाले टाइमर एक साथ काम करेंगे. इससे, टैब को कोड चलाने में लगने वाले समय को इकट्ठा किया जा सकेगा. यह भी कोई नई बात नहीं है. ब्राउज़र, कुछ हद तक ऐसा कई सालों से कर रहे हैं.

ज़्यादा थ्रॉटलिंग

ठीक है, Chrome 88 में नया क्या है. ज़्यादा ट्रॉथलिंग उन टाइमर पर होती है जिन्हें तब शेड्यूल किया जाता है, जब कम से कम ट्रॉथलिंग या ट्रॉथलिंग की कोई भी शर्त लागू न हो और ये सभी शर्तें पूरी होती हों:

  • पेज को पांच मिनट से ज़्यादा समय से छिपा दिया गया है.
  • चेन की संख्या पांच या उससे ज़्यादा है.
  • पेज पर कम से कम 30 सेकंड तक कोई गतिविधि नहीं हुई हो.
  • WebRTC का इस्तेमाल नहीं किया जा रहा है.

इस मामले में, ब्राउज़र हर मिनट में एक बार इस ग्रुप के टाइमर की जांच करेगा. इसका मतलब है कि पहले की तरह ही, हर मिनट की जांच में टाइमर एक साथ काम करेंगे.

समस्या हल करने के तरीके

आम तौर पर, टाइमर के लिए कोई बेहतर विकल्प होता है. इसके अलावा, टाइमर को सीपीयू और बैटरी लाइफ़ के लिए, किसी और चीज़ के साथ जोड़ा जा सकता है.

राज्य के हिसाब से पोल

टाइमर का सबसे ज़्यादा (गलत) इस्तेमाल इसी तरह किया जाता है. इसमें, यह देखने के लिए कि कुछ बदला है या नहीं, लगातार जांच की जाती है या पोल किया जाता है. ज़्यादातर मामलों में, पुश के बराबर की सुविधा होती है. इसमें, बदलाव होने पर आपको इसकी सूचना मिलती है, ताकि आपको बार-बार जांच न करनी पड़े. देखें कि क्या कोई ऐसा इवेंट है जो वही काम करता है.

कुछ उदाहरण:

अगर आपको किसी खास समय पर सूचना दिखानी है, तो सूचना ट्रिगर भी हैं.

ऐनिमेशन

ऐनिमेशन एक विज़ुअल चीज़ है. इसलिए, जब पेज छिपा हो, तो उसे सीपीयू का समय नहीं देना चाहिए.

requestAnimationFrame JavaScript टाइमर के मुकाबले, ऐनिमेशन के काम को शेड्यूल करने में काफ़ी बेहतर है. यह डिवाइस के रीफ़्रेश रेट के साथ सिंक होता है. इससे यह पक्का होता है कि आपको हर डिसप्ले फ़्रेम के लिए सिर्फ़ एक कॉलबैक मिले. साथ ही, आपको उस फ़्रेम को बनाने के लिए ज़्यादा से ज़्यादा समय मिलता है. साथ ही, requestAnimationFrame पेज के दिखने का इंतज़ार करेगा, ताकि पेज छिपे होने पर वह किसी सीपीयू का इस्तेमाल न करे.

अगर आपके पास पूरे ऐनिमेशन को पहले से एलान करने का विकल्प है, तो सीएसएस ऐनिमेशन या वेब ऐनिमेशन एपीआई का इस्तेमाल करें. इनके पास requestAnimationFrame के जैसे ही फ़ायदे होते हैं. हालांकि, ब्राउज़र अपने-आप कॉम्पोज़ करने जैसी अन्य ऑप्टिमाइज़ेशन कर सकता है. साथ ही, आम तौर पर इन्हें इस्तेमाल करना आसान होता है.

अगर आपके ऐनिमेशन का फ़्रेम रेट कम है (जैसे, ब्लिंक करने वाला कर्सर), तो फ़िलहाल टाइमर सबसे अच्छा विकल्प है. हालांकि, दोनों का फ़ायदा पाने के लिए, requestAnimationFrame के साथ टाइमर का इस्तेमाल किया जा सकता है:

function animationInterval(ms, signal, callback) {
  const start = document.timeline.currentTime;

  function frame(time) {
    if (signal.aborted) return;
    callback(time);
    scheduleFrame(time);
  }

  function scheduleFrame(time) {
    const elapsed = time - start;
    const roundedElapsed = Math.round(elapsed / ms) * ms;
    const targetNext = start + roundedElapsed + ms;
    const delay = targetNext - performance.now();
    setTimeout(() => requestAnimationFrame(frame), delay);
  }

  scheduleFrame(start);
}

इस्तेमाल का तरीका:

const controller = new AbortController();

// Create an animation callback every second:
animationInterval(1000, controller.signal, time => {
  console.log('tick!', time);
});

// And stop it:
controller.abort();

टेस्ट करना

यह बदलाव, Chrome 88 (जनवरी 2021) में Chrome इस्तेमाल करने वाले सभी लोगों के लिए चालू हो जाएगा. फ़िलहाल, यह सुविधा Chrome के बीटा, डेवलपर, और कैनरी वर्शन के 50% उपयोगकर्ताओं के लिए चालू है. अगर आपको इसकी जांच करनी है, तो Chrome के बीटा, डेवलपर या कैनरी वर्शन को लॉन्च करते समय, इस कमांड लाइन फ़्लैग का इस्तेमाल करें:

--enable-features="IntensiveWakeUpThrottling:grace_period_seconds/10,OptOutZeroTimeoutTimersFromThrottling,AllowAggressiveThrottlingWithWebSocket"

grace_period_seconds/10 आर्ग्युमेंट की वजह से, पेज के छिपने के 10 सेकंड के बाद, ज़्यादा थ्रॉटलिंग शुरू हो जाती है. यह थ्रॉटलिंग, पेज के छिपने के पांच मिनट बाद शुरू नहीं होती. इससे थ्रॉटलिंग के असर को आसानी से देखा जा सकता है.

आने वाला समय

टाइमर, सीपीयू के ज़्यादा इस्तेमाल का एक सोर्स हैं. इसलिए, हम वेब कॉन्टेंट को बिना किसी रुकावट के चलाने के लिए, टाइमर को कम करने के तरीकों पर काम करते रहेंगे. साथ ही, हम ऐसे एपीआई भी जोड़ेंगे या बदलेंगे जिनसे इस्तेमाल के उदाहरणों को पूरा किया जा सके. निजी तौर पर, मैं कम फ़्रीक्वेंसी वाले ऐनिमेशन कॉलबैक के पक्ष में, animationInterval की ज़रूरत को खत्म करना चाहूंगा. अगर आपका कोई सवाल है, तो कृपया Twitter पर हमसे संपर्क करें!

हेडर की फ़ोटो, Unsplash पर Heather Zabriskie की है.