शेड्यूलr.yield ऑरिजिन ट्रायल पेश है

वेबसाइट की परफ़ॉर्मेंस के लिए, उपयोगकर्ता का इनपुट का तुरंत जवाब देने वाली वेबसाइटें बनाना सबसे मुश्किल काम रहा है. Chrome की टीम, वेब डेवलपर को इस चुनौती से निपटने में मदद करने के लिए लगातार काम कर रही है. इस साल ही, यह एलान किया गया था कि इंटरैक्शन टू नेक्स्ट पेंट (आईएनपी) मेट्रिक को एक्सपेरिमेंट के तौर पर इस्तेमाल होने वाली मेट्रिक से हटाकर, 'लंबित' स्टेटस पर सेट कर दिया जाएगा. अब यह मार्च 2024 में, Core Web Vital के तौर पर क्लिक के बाद रिस्पॉन्स में लगा समय (एफ़आईडी) मेट्रिक की जगह लेगी.

वेब डेवलपर को ऐसे नए एपीआई उपलब्ध कराने के लिए Chrome टीम लगातार काम कर रही है जिनकी मदद से, वे अपनी वेबसाइटों को ज़्यादा से ज़्यादा तेज़ी से लोड होने वाली बना सकें. फ़िलहाल, Chrome टीम Chrome के वर्शन 115 से scheduler.yield के लिए ऑरिजिन ट्रायल चला रही है. scheduler.yield, शेड्यूलर एपीआई में जोड़ा गया एक नया फ़ंक्शन है. यह उन तरीकों की तुलना में, मुख्य थ्रेड को कंट्रोल वापस देने का आसान और बेहतर तरीका उपलब्ध कराता है जिन पर अब तक भरोसा किया जाता रहा है.

उपलब्ध होने पर

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

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

लंबे समय तक चलने वाले टास्क की वजह से, पेज पर रिस्पॉन्स मिलने में ज़्यादा समय लगता है. ऐसा इसलिए होता है, क्योंकि ये टास्क, उपयोगकर्ता के इनपुट का जवाब देने में ब्राउज़र की क्षमता में देरी करते हैं. लंबे टास्क जितनी बार होते हैं और जितने ज़्यादा समय तक चलते हैं, उपयोगकर्ताओं को यह लग सकता है कि पेज ठीक से काम नहीं कर रहा है. ऐसा भी हो सकता है कि उन्हें लगे कि पेज पूरी तरह से काम नहीं कर रहा है.

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

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

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

मौजूदा यिल्डिंग रणनीतियों से जुड़ी समस्या

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

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

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

  1. सबसे ऊपर मौजूद, टास्क समय-समय पर चलाएं लेबल वाले बटन पर क्लिक करें. इससे, टास्क को ब्लॉक करने के लिए शेड्यूल किया जाएगा, ताकि वे समय-समय पर चल सकें. इस बटन पर क्लिक करने से, टास्क लॉग में कई मैसेज दिखेंगे. इनमें लिखा होगा कि setInterval के साथ ब्लॉक करने का टास्क पूरा हुआ.
  2. इसके बाद, हर बार setTimeout के साथ लूप चलाएं लेबल वाले बटन पर क्लिक करें.

आपको दिखेगा कि डेमो के सबसे नीचे मौजूद बॉक्स में कुछ ऐसा लिखा होगा:

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 के साथ यिल्डिंग करने पर होता है. यह लूप पांच आइटम को प्रोसेस करता है. साथ ही, हर आइटम को प्रोसेस करने के बाद setTimeout दिखाता है.

इससे वेब पर होने वाली एक सामान्य समस्या के बारे में पता चलता है: ऐसा अक्सर होता है कि कोई स्क्रिप्ट—खास तौर पर तीसरे पक्ष की स्क्रिप्ट—एक टाइमर फ़ंक्शन रजिस्टर करती है, जो कुछ समय के अंतराल पर काम करता है. setTimeout के साथ यिल्डिंग करने पर, "टास्क के आखिर में" होने वाली कार्रवाई का मतलब है कि टास्क के अन्य सोर्स से मिले टास्क, लूप के बाकी काम से पहले पूरे किए जा सकते हैं.

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

scheduler.yield में जाएं

scheduler.yield, Chrome के 115 वर्शन के बाद से, फ़्लैग के पीछे एक्सपेरिमेंट के तौर पर उपलब्ध वेब प्लैटफ़ॉर्म की सुविधा के तौर पर उपलब्ध है. आपके मन में यह सवाल आ सकता है कि "जब setTimeout पहले से ही ऐसा करता है, तो मुझे यिल्ड करने के लिए किसी खास फ़ंक्शन की ज़रूरत क्यों है?"

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

scheduler.yield एक ऐसा फ़ंक्शन है जो मुख्य थ्रेड को दिखाता है और कॉल किए जाने पर Promise दिखाता है. इसका मतलब है कि इसे async फ़ंक्शन में await किया जा सकता है:

async function yieldy () {
  // Do some work...
  // ...

  // Yield!
  await scheduler.yield();

  // Do some more work...
  // ...
}

scheduler.yield को काम करते हुए देखने के लिए, यह तरीका अपनाएं:

  1. chrome://flags पर नेविगेट करें.
  2. Experimental Web Platform features एक्सपेरिमेंट को चालू करें. ऐसा करने के बाद, आपको Chrome को रीस्टार्ट करना पड़ सकता है.
  3. डेमो पेज पर जाएं या इस सूची के बाद, एम्बेड किए गए इसके वर्शन का इस्तेमाल करें.
  4. सबसे ऊपर मौजूद, टास्क समय-समय पर चलाएं लेबल वाले बटन पर क्लिक करें.
  5. आखिर में, Run loop, yielding with scheduler.yield on 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 का इस्तेमाल करके जनरेट किए गए डेमो के उलट, आपको दिखेगा कि लूप हर बार जनरेट होने के बाद भी, बचे हुए काम को क्यू के आखिर में नहीं भेजता, बल्कि क्यू के शुरू में भेजता है. इससे आपको दोनों फ़ायदे मिलते हैं: अपनी वेबसाइट पर इनपुट के जवाब देने की क्षमता को बेहतर बनाने के लिए, यिल्ड किया जा सकता है. साथ ही, यह भी पक्का किया जा सकता है कि यिल्ड करने के बाद पूरा किया जाने वाला काम देर से न हो.

इसे आज़माएं!

अगर आपको scheduler.yield दिलचस्प लगता है और आपको इसे आज़माना है, तो Chrome के वर्शन 115 से इसे दो तरीकों से आज़माया जा सकता है:

  1. अगर आपको scheduler.yield को स्थानीय तौर पर आज़माना है, तो Chrome के पता बार में chrome://flags टाइप करें और Enter दबाएं. इसके बाद, एक्सपेरिमेंट के तौर पर उपलब्ध वेब प्लैटफ़ॉर्म की सुविधाएं सेक्शन में जाकर, ड्रॉप-डाउन से चालू करें को चुनें. इससे scheduler.yield (और अन्य एक्सपेरिमेंटल सुविधाएं) सिर्फ़ आपके Chrome इंस्टेंस में उपलब्ध होंगी.
  2. अगर आपको सार्वजनिक तौर पर ऐक्सेस किए जा सकने वाले ऑरिजिन पर, Chromium का इस्तेमाल करने वाले असली उपयोगकर्ताओं के लिए scheduler.yield की सुविधा चालू करनी है, तो आपको scheduler.yield के ऑरिजिन ट्रायल के लिए साइन अप करना होगा. इससे आपको तय समय के लिए, सुझाई गई सुविधाओं को सुरक्षित तरीके से आज़माने का मौका मिलता है. साथ ही, Chrome टीम को इस बारे में अहम जानकारी मिलती है कि उन सुविधाओं का इस्तेमाल कैसे किया जाता है. ऑरिजिन ट्रायल के काम करने के तरीके के बारे में ज़्यादा जानने के लिए, यह गाइड पढ़ें.

scheduler.yield का इस्तेमाल कैसे किया जाए, यह आपके लक्ष्यों पर निर्भर करता है. हालांकि, आपको ऐसे ब्राउज़र को भी सपोर्ट करना होगा जो इसे लागू नहीं करते. आधिकारिक पॉलीफ़िल का इस्तेमाल किया जा सकता है. पॉलीफ़िल तब मददगार होता है, जब आपकी स्थिति में ये बातें लागू होती हैं:

  1. टास्क शेड्यूल करने के लिए, आपके ऐप्लिकेशन में पहले से ही scheduler.postTask का इस्तेमाल किया जा रहा है.
  2. आपको टास्क और यिल्डिंग की प्राथमिकताएं सेट करने की सुविधा चाहिए.
  3. आपको scheduler.postTask क्लास का इस्तेमाल करके, टास्क रद्द करने या उनकी प्राथमिकता बदलने की सुविधा चाहिए. यह सुविधा scheduler.postTask API देता है.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 काम नहीं करता वे "फ़्रंट ऑफ़ क्यू" व्यवहार के बिना काम करेंगे. अगर इसका मतलब यह है कि आपको बिल्कुल भी यिल्ड नहीं करना है, तो कोई दूसरा तरीका आज़माएं. इसमें scheduler.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.yield एक उपयोगी एपीआई लगता है, तो कृपया इसे बेहतर बनाने के लिए हमारी रिसर्च में हिस्सा लें. साथ ही, इसे और बेहतर बनाने के बारे में सुझाव/राय दें या शिकायत करें.

Unsplash से ली गई हीरो इमेज. इसे जोनाथन एलिसन ने बनाया है.