लंबे टास्क को अलग-अलग करने के लिए, scheduler.yield() का इस्तेमाल करना

पब्लिश करने की तारीख: 6 मार्च, 2025

Browser Support

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

Source

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

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

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

async function respondToUserClick() {
  giveImmediateFeedback();
  await scheduler.yield(); // Yield to the main thread.
  slowerComputation();
}

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

टास्क को अलग-अलग करने के लिए, setTimeout या scheduler.postTask जैसे फ़ंक्शन का भी इस्तेमाल किया जा सकता है. हालांकि, ये फ़ंक्शन आम तौर पर, पहले से मौजूद किसी नए टास्क के बाद चलते हैं. इससे, मुख्य थ्रेड को सबमिशन करने और अपना काम पूरा करने में काफ़ी देरी हो सकती है.

'नतीजा दें' के बाद, प्राथमिकता वाले फ़ंक्शन को फिर से शुरू करना

scheduler.yield, टास्क को प्राथमिकता के हिसाब से शेड्यूल करने वाले एपीआई का हिस्सा है. वेब डेवलपर के तौर पर, हम आम तौर पर इस बात के बारे में नहीं बताते कि इवेंट लूप, टास्क को किस क्रम में चलाता है. हालांकि, टास्क की प्राथमिकता हमेशा मौजूद होती है. जैसे, setTimeout कॉलबैक की सूची में शामिल किसी भी कॉलबैक के बाद चलने वाला requestIdleCallback कॉलबैक या आम तौर पर setTimeout(callback, 0) के साथ सूची में शामिल किसी टास्क से पहले चलने वाला ट्रिगर किया गया इनपुट इवेंट लिसनर.

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

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

यहां एक उदाहरण दिया गया है: दो फ़ंक्शन, setTimeout का इस्तेमाल करके अलग-अलग टास्क में चलाने के लिए कतार में लगाए गए हैं.

setTimeout(myJob);
setTimeout(someoneElsesJob);

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

DevTools में यह बदलाव ऐसा दिख सकता है:

Chrome DevTools के परफ़ॉर्मेंस पैनल में दिखाए गए दो टास्क. दोनों टास्क लंबे हैं. 'myJob' फ़ंक्शन, पहले टास्क को पूरा करता है और 'someoneElsesJob' फ़ंक्शन, दूसरे टास्क को पूरा करता है.

myJob को लंबे टास्क के तौर पर फ़्लैग किया गया है. इस वजह से, टास्क पूरा होने तक ब्राउज़र किसी और काम नहीं कर सकता. मान लें कि यह पहले पक्ष की स्क्रिप्ट से है, तो हम इसे अलग-अलग हिस्सों में बांट सकते हैं:

function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with setTimeout() to break up long task, then run part2.
  setTimeout(myJobPart2, 0);
}

myJobPart2 को myJob के अंदर setTimeout के साथ चलाने के लिए शेड्यूल किया गया था. हालांकि, यह शेड्यूलिंग someoneElsesJob के पहले से शेड्यूल होने के बाद चलती है. इसलिए, इसे लागू करने का तरीका यहां बताया गया है:

Chrome DevTools के परफ़ॉर्मेंस पैनल में दिखाए गए तीन टास्क. पहला टास्क, 'myJobPart1' फ़ंक्शन को चला रहा है. दूसरा टास्क, 'someoneElsesJob' फ़ंक्शन को चला रहा है, जो लंबा है. तीसरा टास्क, 'myJobPart2' फ़ंक्शन को चला रहा है.

हमने टास्क को setTimeout के साथ बांटा है, ताकि myJob के बीच में ब्राउज़र रिस्पॉन्सिव हो सके. हालांकि, अब myJob का दूसरा हिस्सा सिर्फ़ someoneElsesJob के खत्म होने के बाद चलता है.

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

scheduler.yield() डालें. इससे, किसी फ़ंक्शन को फिर से शुरू करने की प्रोसेस, उससे मिलते-जुलते किसी दूसरे टास्क को शुरू करने की प्रोसेस की तुलना में थोड़ी ज़्यादा प्राथमिकता वाली सूची में शामिल हो जाती है. अगर myJob का इस्तेमाल करने के लिए इसे बदला जाता है, तो:

async function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with scheduler.yield() to break up long task, then run part2.
  await scheduler.yield();
  myJobPart2();
}

अब यह ऐसा दिखता है:

Chrome DevTools के परफ़ॉर्मेंस पैनल में दिखाए गए दो टास्क. दोनों टास्क लंबे हैं. 'myJob' फ़ंक्शन, पहले टास्क को पूरा करता है और 'someoneElsesJob' फ़ंक्शन, दूसरे टास्क को पूरा करता है.

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

प्राथमिकता इनहेरिटेंस

टास्क को प्राथमिकता के हिसाब से शेड्यूल करने वाले बड़े एपीआई के हिस्से के तौर पर, scheduler.yield(), scheduler.postTask() में उपलब्ध साफ़ तौर पर बताई गई प्राथमिकताओं के साथ अच्छी तरह से काम करता है. साफ़ तौर पर प्राथमिकता सेट किए बिना, scheduler.postTask() कॉलबैक में scheduler.yield(), पिछले उदाहरण की तरह ही काम करेगा.

हालांकि, अगर कोई प्राथमिकता सेट की गई है, जैसे कि 'background' की कम प्राथमिकता का इस्तेमाल करना:

async function lowPriorityJob() {
  part1();
  await scheduler.yield();
  part2();
}

scheduler.postTask(lowPriorityJob, {priority: 'background'});

टास्क को शेड्यूल करने के लिए, प्राथमिकता को अन्य 'background' टास्क से ज़्यादा रखा जाएगा. इससे, किसी भी लंबित 'background' टास्क से पहले, प्राथमिकता के हिसाब से टास्क को पूरा किया जा सकेगा. हालांकि, यह अन्य डिफ़ॉल्ट या ज़्यादा प्राथमिकता वाले टास्क से कम प्राथमिकता वाला टास्क बना रहेगा.'background'

इसका मतलब है कि अगर आपने कम प्राथमिकता वाले काम को 'background' scheduler.postTask() (या requestIdleCallback) के साथ शेड्यूल किया है, तो scheduler.yield() के बाद भी काम तब तक रुका रहेगा, जब तक ज़्यादातर अन्य टास्क पूरे नहीं हो जाते और मुख्य थ्रेड को चलाने के लिए खाली नहीं हो जाता. कम प्राथमिकता वाले काम में, यही करना होता है.

एपीआई का इस्तेमाल कैसे करें

फ़िलहाल, scheduler.yield() सिर्फ़ Chromium कोड वाले ब्राउज़र में उपलब्ध है. इसलिए, इसका इस्तेमाल करने के लिए, आपको अन्य ब्राउज़र के लिए, फ़ीचर का पता लगाना होगा और आउटपुट पाने के लिए दूसरे तरीके का इस्तेमाल करना होगा.

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

अगर आपको पॉलीफ़िल का इस्तेमाल नहीं करना है, तो setTimeout() का इस्तेमाल करके फ़ंक्शन को पूरा होने दें. हालांकि, ऐसा करने पर, प्राथमिकता वाले फ़ंक्शन को पूरा होने में ज़्यादा समय लगेगा. इसके अलावा, अगर आपको यह तरीका पसंद नहीं है, तो ऐसे ब्राउज़र में फ़ंक्शन को पूरा होने न दें जिनमें यह काम नहीं करता. ज़्यादा जानकारी के लिए, scheduler.yield() लंबे टास्क ऑप्टिमाइज़ करने के बारे में दस्तावेज़ देखें.

wicg-task-scheduling टाइप का इस्तेमाल, टाइप की जांच करने और IDE की सहायता पाने के लिए भी किया जा सकता है. ऐसा तब किया जा सकता है, जब scheduler.yield() की सुविधा का पता लगाने और फ़ॉलबैक को खुद जोड़ने की कोशिश की जा रही हो.

ज़्यादा जानें

एपीआई और टास्क की प्राथमिकताओं और scheduler.postTask() के साथ इसके इंटरैक्ट करने के तरीके के बारे में ज़्यादा जानने के लिए, MDN पर scheduler.yield() और टास्क की प्राथमिकता के हिसाब से शेड्यूल करने वाले दस्तावेज़ देखें.

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