लंबे टास्क ऑप्टिमाइज़ करें

आपको "मुख्य थ्रेड को ब्लॉक न करें" और "लंबे टास्क को छोटे-छोटे टास्क में बांटें" के बारे में बताया गया है. हालांकि, इन बातों का क्या मतलब है?

पब्लिश किया गया: 30 सितंबर, 2022, पिछली बार अपडेट किया गया: 19 दिसंबर, 2024

JavaScript ऐप्लिकेशन को तेज़ बनाए रखने के लिए, आम तौर पर ये सुझाव दिए जाते हैं:

  • "मुख्य थ्रेड को ब्लॉक न करें."
  • "बड़े टास्क को छोटे-छोटे टास्क में बांटें."

यह एक बेहतरीन सलाह है, लेकिन इसमें क्या काम करना होगा? कम JavaScript का इस्तेमाल करना अच्छा है, लेकिन क्या इससे उपयोगकर्ता इंटरफ़ेस अपने-आप ज़्यादा तेज़ी से काम करने लगते हैं? हो सकता है, लेकिन शायद नहीं.

JavaScript में टास्क को ऑप्टिमाइज़ करने का तरीका समझने के लिए, आपको सबसे पहले यह जानना होगा कि टास्क क्या होते हैं और ब्राउज़र उन्हें कैसे हैंडल करता है.

टास्क क्या होता है?

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

Chrome के DevTools के परफ़ॉर्मेंस प्रोफ़ाइलर में, किसी टास्क को विज़ुअलाइज़ किया गया है. टास्क, स्टैक में सबसे ऊपर है. इसमें क्लिक इवेंट हैंडलर, फ़ंक्शन कॉल, और इसके नीचे अन्य आइटम मौजूद हैं. इस टास्क में, दाईं ओर कुछ रेंडरिंग का काम भी शामिल है.
यह click इवेंट हैंडलर से शुरू किया गया टास्क है. इसे Chrome DevTools के परफ़ॉर्मेंस प्रोफ़ाइलर में दिखाया गया है.

JavaScript से जुड़े टास्क, परफ़ॉर्मेंस पर कई तरह से असर डालते हैं:

  • जब कोई ब्राउज़र स्टार्टअप के दौरान JavaScript फ़ाइल डाउनलोड करता है, तो वह उस JavaScript को पार्स और कंपाइल करने के लिए टास्क को लाइन में लगाता है, ताकि उसे बाद में लागू किया जा सके.
  • पेज के चालू रहने के दौरान, अन्य समय में टास्क तब लाइन में लग जाते हैं, जब JavaScript काम करती है. जैसे, इवेंट हैंडलर के ज़रिए इंटरैक्शन का जवाब देना, JavaScript की मदद से ऐनिमेशन बनाना, और बैकग्राउंड में होने वाली गतिविधि, जैसे कि आंकड़ों को इकट्ठा करना.

वेब वर्कर और मिलते-जुलते एपीआई को छोड़कर, यह सब मुख्य थ्रेड पर होता है.

मुख्य थ्रेड क्या है?

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

मुख्य थ्रेड, एक बार में सिर्फ़ एक टास्क प्रोसेस कर सकती है. अगर किसी टास्क को पूरा होने में 50 मिलीसेकंड से ज़्यादा समय लगता है, तो उसे लॉन्ग टास्क कहा जाता है. अगर किसी टास्क को पूरा होने में 50 मिलीसेकंड से ज़्यादा समय लगता है, तो टास्क को पूरा होने में लगे कुल समय में से 50 मिलीसेकंड घटाने पर, टास्क का ब्लॉकिंग पीरियड मिलता है.

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

Chrome के DevTools के परफ़ॉर्मेंस प्रोफ़ाइलर में लंबे समय तक चलने वाला टास्क. टास्क के ब्लॉकिंग हिस्से (50 मिलीसेकंड से ज़्यादा) को लाल रंग की डायगोनल स्ट्राइप वाले पैटर्न से दिखाया गया है.
Chrome के परफ़ॉर्मेंस प्रोफ़ाइलर में दिखाया गया एक लंबा टास्क. लंबे टास्क को टास्क के कोने में मौजूद लाल रंग के त्रिकोण से दिखाया जाता है. साथ ही, टास्क के उस हिस्से को लाल रंग की तिरछी पट्टियों के पैटर्न से भरा जाता है जो टास्क को ब्लॉक करता है.

मुख्य थ्रेड को ज़्यादा देर तक ब्लॉक होने से रोकने के लिए, लंबे टास्क को कई छोटे-छोटे टास्क में बांटा जा सकता है.

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

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

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

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

अब आपको पता चल गया है कि टास्क को छोटे-छोटे हिस्सों में बांटना क्यों ज़रूरी है. अब JavaScript में ऐसा करने का तरीका जानें.

टास्क मैनेज करने की रणनीतियां

सॉफ़्टवेयर आर्किटेक्चर में, काम को छोटे-छोटे फ़ंक्शन में बांटने का सुझाव दिया जाता है:

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

इस उदाहरण में, saveSettings() नाम का एक फ़ंक्शन है. यह फ़ंक्शन, पांच फ़ंक्शन को कॉल करता है. ये फ़ंक्शन, फ़ॉर्म की पुष्टि करने, स्पिनर दिखाने, ऐप्लिकेशन के बैकएंड को डेटा भेजने, यूज़र इंटरफ़ेस को अपडेट करने, और आंकड़ों को भेजने के लिए इस्तेमाल किए जाते हैं.

आइडिया के तौर पर, saveSettings() को अच्छी तरह से डिज़ाइन किया गया है. अगर आपको इनमें से किसी फ़ंक्शन को डीबग करना है, तो प्रोजेक्ट ट्री पर जाकर यह पता लगाया जा सकता है कि हर फ़ंक्शन क्या करता है. इस तरह से काम को बांटने से, प्रोजेक्ट को नेविगेट करना और मैनेज करना आसान हो जाता है.

हालांकि, यहां एक समस्या यह है कि JavaScript इन सभी फ़ंक्शन को अलग-अलग टास्क के तौर पर नहीं चलाता है, क्योंकि इन्हें saveSettings() फ़ंक्शन के अंदर एक्ज़ीक्यूट किया जाता है. इसका मतलब है कि ये पांचों फ़ंक्शन, एक टास्क के तौर पर काम करेंगे.

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

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

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

कोड को मैन्युअल तरीके से चलाने में देरी करना

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

डेवलपर, कामों को छोटे-छोटे हिस्सों में बांटने के लिए 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() का इस्तेमाल करना समस्या पैदा कर सकता है. साथ ही, नेस्ट किए गए setTimeout() के पांच राउंड के बाद, ब्राउज़र हर अतिरिक्त setTimeout() के लिए कम से कम पांच मिलीसेकंड का इंतज़ार करने का समय तय कर देगा.

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

एक खास यिल्डिंग एपीआई: scheduler.yield()

Browser Support

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

Source

scheduler.yield() एक ऐसा एपीआई है जिसे खास तौर पर ब्राउज़र में मुख्य थ्रेड को मैनेज करने के लिए डिज़ाइन किया गया है.

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

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

async function saveSettings () {
  // Do critical work that is user-visible:
  validateForm();
  showSpinner();
  updateUI();

  // Yield to the main thread:
  await scheduler.yield()

  // Work that isn't user-visible, continued in a separate task:
  saveToDatabase();
  sendAnalytics();
}
Chrome के परफ़ॉर्मेंस प्रोफ़ाइलर में दिखाया गया saveSettings फ़ंक्शन, जिसे अब दो टास्क में बांट दिया गया है. पहले टास्क में दो फ़ंक्शन कॉल किए जाते हैं. इसके बाद, लेआउट और पेंट का काम पूरा होता है. इससे उपयोगकर्ता को जवाब दिखता है. इस वजह से, क्लिक इवेंट 64 मिलीसेकंड में पूरा हो जाता है. दूसरा टास्क, आखिरी तीन फ़ंक्शन को कॉल करता है.
फ़ंक्शन saveSettings() को अब दो टास्क में बांट दिया गया है. इस वजह से, लेआउट और पेंट को टास्क के बीच में चलाया जा सकता है. इससे उपयोगकर्ता को विज़ुअल रिस्पॉन्स तेज़ी से मिलता है. इसे अब बहुत कम समय में पॉइंटर इंटरैक्शन से मापा जाता है.

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

इससे, टास्क के अन्य सोर्स से मिले कोड को आपके कोड के एक्ज़ीक्यूशन के क्रम में रुकावट डालने से रोका जा सकता है. जैसे, तीसरे पक्ष की स्क्रिप्ट से मिले टास्क.

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

अलग-अलग ब्राउज़र पर काम करने की सुविधा

scheduler.yield() अभी सभी ब्राउज़र पर काम नहीं करता है. इसलिए, फ़ॉलबैक की ज़रूरत होती है.

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

इसके अलावा, कम जटिल वर्शन को कुछ लाइनों में लिखा जा सकता है. इसमें सिर्फ़ setTimeout को Promise में रैप किया जाता है. अगर scheduler.yield() उपलब्ध नहीं है, तो इसे फ़ॉलबैक के तौर पर इस्तेमाल किया जाता है.

function yieldToMain () {
  if (globalThis.scheduler?.yield) {
    return scheduler.yield();
  }

  // Fall back to yielding with setTimeout.
  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
}

scheduler.yield() की सुविधा के बिना काम करने वाले ब्राउज़र में, प्राथमिकता के आधार पर जारी रखने की सुविधा काम नहीं करेगी. हालांकि, ब्राउज़र को रिस्पॉन्सिव बनाए रखने के लिए, वे अब भी काम करेंगे.

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

इसे सुविधा का पता लगाकर और एक लाइन में लिखे गए कोड में एक माइक्रोटास्क के पूरा होने का इंतज़ार करके किया जा सकता है:

// Yield to the main thread if scheduler.yield() is available.
await globalThis.scheduler?.yield?.();

scheduler.yield() की मदद से, लंबे समय तक चलने वाले काम को छोटे-छोटे हिस्सों में बांटना

scheduler.yield() का इस्तेमाल करने के इन तरीकों का फ़ायदा यह है कि इसे किसी भी async फ़ंक्शन में इस्तेमाल किया जा सकता है.await

उदाहरण के लिए, अगर आपको कई ऐसे जॉब चलाने हैं जो अक्सर एक लंबे टास्क में बदल जाते हैं, तो टास्क को छोटे-छोटे हिस्सों में बांटने के लिए, यिल्ड का इस्तेमाल किया जा सकता है.

async function runJobs(jobQueue) {
  for (const job of jobQueue) {
    // Run the job:
    job();

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

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

हालांकि, इससे बेहतर तरीके से यिल्डिंग नहीं हो पाती. scheduler.yield() तेज़ और असरदार है, लेकिन इसमें कुछ ओवरहेड होता है. अगर jobQueue में कुछ काम बहुत कम समय के लिए हैं, तो ओवरहेड की वजह से, काम को शुरू करने और रोकने में ज़्यादा समय लग सकता है. ऐसा तब होता है, जब काम को पूरा करने में कम समय लगता है.

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

async function runJobs(jobQueue, deadline=50) {
  let lastYield = performance.now();

  for (const job of jobQueue) {
    // Run the job:
    job();

    // If it's been longer than the deadline, yield to the main thread:
    if (performance.now() - lastYield > deadline) {
      await yieldToMain();
      lastYield = performance.now();
    }
  }
}

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

Chrome DevTools के परफ़ॉर्मेंस पैनल में, कई जॉब फ़ंक्शन दिखाए गए हैं. इन्हें कई टास्क में बांटा गया है
एक से ज़्यादा टास्क में बांटे गए काम.

isInputPending() का इस्तेमाल न करें

Browser Support

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

Source

isInputPending() एपीआई से यह पता चलता है कि किसी उपयोगकर्ता ने पेज से इंटरैक्ट करने की कोशिश की है या नहीं. साथ ही, यह सिर्फ़ तब नतीजे दिखाता है, जब कोई इनपुट प्रोसेस होना बाकी हो.

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

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

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

नतीजा

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

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

scheduler.yield(), टास्क शेड्यूलिंग से जुड़े scheduler.postTask(), और टास्क को प्राथमिकता देने के बारे में ज़्यादा जानने के लिए, Prioritized Task Scheduling API के दस्तावेज़ देखें.

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

इस गाइड की तकनीकी जांच करने के लिए, फ़िलिप वॉल्टन को खास तौर पर धन्यवाद.

थंबनेल इमेज, Unsplash से ली गई है. इसका क्रेडिट Amirali Mirhashemian को जाता है.