Chrome DevTools की मदद से एसिंक्रोनस JavaScript को डीबग करना

परिचय

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

अच्छी बात यह है कि अब Chrome DevTools में, ऐसिंक्रोनस JavaScript कॉलबैक का पूरा कॉल स्टैक देखा जा सकता है!

असाइनमेंट के लिए एक साथ काम करने वाली प्रोसेस से हटाए गए कॉल स्टैक के बारे में खास जानकारी देने वाला टीज़र.
एक साथ काम नहीं करने वाले कॉल स्टैक के बारे में खास जानकारी देने वाला टीज़र. (हम जल्द ही इस डेमो के फ़्लो के बारे में बताएंगे.)

DevTools में असाइन किए गए कॉल स्टैक की सुविधा चालू करने के बाद, आपके पास समय के अलग-अलग पलों पर अपने वेब ऐप्लिकेशन की स्थिति के बारे में जानने का विकल्प होगा. कुछ इवेंट लिसनर, setInterval,setTimeout, XMLHttpRequest, प्रॉमिस, requestAnimationFrame, MutationObservers वगैरह के लिए पूरा स्टैक ट्रेस देखें.

स्टैक ट्रेस पर चलते समय, रनटाइम की प्रोसेस के उस खास पॉइंट पर किसी भी वैरिएबल की वैल्यू का विश्लेषण भी किया जा सकता है. यह स्मार्टवॉच पर इस्तेमाल किए जाने वाले एक्सप्रेशन के लिए, टाइम मशीन की तरह है!

आइए, इस सुविधा को चालू करें और इनमें से कुछ स्थितियों पर नज़र डालें.

Chrome में एक साथ काम नहीं करने वाली प्रोसेस को डीबग करने की सुविधा चालू करना

इस नई सुविधा को Chrome में चालू करके आज़माएं. Chrome Canary DevTools के सोर्स पैनल पर जाएं.

दाईं ओर कॉल स्टैक पैनल के बगल में, "असाइनमेंट के साथ-साथ अन्य काम करना" के लिए एक नया चेकबॉक्स है. असाइनमेंट के साथ-साथ डीबग करने की सुविधा को चालू या बंद करने के लिए, चेकबॉक्स को टॉगल करें. हालांकि, इसे चालू करने के बाद, शायद आप इसे कभी बंद न करना चाहें.

असाइनमेंट को सिंक न करने की सुविधा को चालू या बंद करें.

देर से होने वाले टाइमर इवेंट और XHR रिस्पॉन्स कैप्चर करना

आपको यह मैसेज, Gmail में पहले भी दिख चुका होगा:

Gmail, ईमेल भेजने की कोशिश फिर से कर रहा है.

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

हमने Gmail के मॉक उदाहरण की मदद से, उस फ़्लो को फिर से बनाया है, ताकि यह देखा जा सके कि असाइन किए गए कॉल स्टैक, देर से होने वाले टाइमर इवेंट और XHR रिस्पॉन्स का विश्लेषण कैसे कर सकते हैं. ऊपर दिए गए लिंक में, JavaScript का पूरा कोड मिल सकता है. हालांकि, इसका फ़्लो इस तरह है:

नकली Gmail खाते के उदाहरण का फ़्लो चार्ट.
ऊपर दिए गए डायग्राम में, नीले रंग से हाइलाइट किए गए तरीके, DevTool की इस नई सुविधा के लिए सबसे ज़्यादा फ़ायदेमंद हैं. ऐसा इसलिए है, क्योंकि ये तरीके अलग-अलग समय पर काम करते हैं.

DevTools के पिछले वर्शन में, कॉल स्टैक पैनल को सिर्फ़ देखने पर, postOnFail() में ब्रेकपॉइंट से आपको यह जानकारी नहीं मिलती कि postOnFail() को कहां से कॉल किया जा रहा है. हालांकि, असाइनमेंट के लिए एक से ज़्यादा स्टैक इस्तेमाल करने की सुविधा चालू करने पर, इस अंतर को देखें:

पहले
Gmail के मॉक उदाहरण में, ब्रेकपॉइंट को असाइन किया गया है. इसमें असाइन किए गए कॉल स्टैक नहीं हैं.
कॉल स्टैक पैनल, एसिंक्रोनस कॉल बिना चालू किया गया.

यहां देखा जा सकता है कि postOnFail() को AJAX कॉलबैक से शुरू किया गया था, लेकिन कोई और जानकारी नहीं है.

इसके बाद
Gmail के मॉक उदाहरण में, असाइन किए गए कॉल स्टैक के साथ ब्रेकपॉइंट सेट किया गया.
कॉल स्टैक पैनल, एसिंक्रोनस के साथ चालू हो जाता है.

यहां देखा जा सकता है कि XHR को submitHandler() से शुरू किया गया था. बढ़िया!

असाइन किए गए कॉल स्टैक चालू होने पर, पूरा कॉल स्टैक देखा जा सकता है. इससे यह आसानी से पता चलता है कि अनुरोध submitHandler() (जो सबमिट बटन पर क्लिक करने के बाद होता है) से शुरू हुआ था या retrySubmit() (जो setTimeout() देरी के बाद होता है) से:

submitHandler()
Gmail के मॉक उदाहरण में, असाइन किए गए कॉल स्टैक के साथ ब्रेकपॉइंट सेट करना
retrySubmit()
Gmail के मॉक उदाहरण में, असाइन किए गए कॉल स्टैक के साथ सेट किया गया दूसरा ब्रेकपॉइंट

वॉच एक्सप्रेशन को अलग-अलग समय पर देखना

पूरे कॉल स्टैक को वॉक करने पर, आपके देखे गए एक्सप्रेशन भी अपडेट हो जाएंगे, ताकि उस समय की स्थिति को दिखाया जा सके!

असाइन किए गए कॉल स्टैक के साथ वॉच एक्सप्रेशन का इस्तेमाल करने का उदाहरण

पिछले स्कोप के कोड का आकलन करना

एक्सप्रेशन को सिर्फ़ देखने के अलावा, DevTools के JavaScript कंसोल पैनल में जाकर, पिछले स्कोप के कोड के साथ इंटरैक्ट किया जा सकता है.

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

असाइन किए गए कॉल स्टैक के साथ JavaScript कंसोल का इस्तेमाल करने का उदाहरण.
अपने कोड को डीबग करने के लिए, JavaScript कंसोल का इस्तेमाल एसिंक्रोनस कॉल स्टैक के साथ करें. ऊपर दिया गया डेमो यहां देखा जा सकता है.

एक्सप्रेशन में बदलाव करने के लिए, DevTools में बने रहने से आपको सोर्स कोड पर वापस स्विच करने, बदलाव करने, और ब्राउज़र को रीफ़्रेश करने में लगने वाला समय बचेगा.

चेन किए गए प्रॉमिस रिज़ॉल्यूशन को अनरॉल करना

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

यहां जैक के async-best-example.html उदाहरण में, कॉल स्टैक को वॉक करने का एक छोटा ऐनिमेशन दिया गया है.

पहले
प्रोमिस के उदाहरण में, ब्रेकपॉइंट सेट किया गया है. इसमें असाइनिक कॉल स्टैक नहीं हैं
कॉल स्टैक पैनल, एसिंक्रोनस कॉल बिना चालू किया गया.

ध्यान दें कि कॉल स्टैक पैनल में, प्रॉमिस को डीबग करने के दौरान बहुत कम जानकारी दिखती है.

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

वाह! ऐसे वादे. बहुत ज़्यादा कॉलबैक.

अपने वेब ऐनिमेशन के बारे में अहम जानकारी पाना

आइए, HTML5Rocks के संग्रह के बारे में ज़्यादा जानें. क्या आपको पॉल लुइस का requestAnimationFrame की मदद से, बेहतर, ज़्यादा बेहतर, और तेज़ ऐनिमेशन लेख याद है?

requestAnimationFrame डेमो खोलें और post.html के update() तरीके की शुरुआत में ब्रेकपॉइंट जोड़ें. यह तरीका, लाइन 874 के आस-पास होता है. असाइन किए गए कॉल स्टैक की मदद से, हमें requestAnimationFrame के बारे में ज़्यादा जानकारी मिलती है. इसमें, स्क्रोल इवेंट कॉलबैक तक वापस जाने की सुविधा भी शामिल है.

पहले
requestAnimationFrame के उदाहरण में, ब्रेकपॉइंट सेट किया गया है. इसमें एक साथ काम नहीं करने वाले कॉल स्टैक नहीं हैं.
कॉल स्टैक पैनल, एसिंक्रोनस कॉल बिना चालू किया गया.
इसके बाद
एसिंक्रोनस कॉल स्टैक के साथ requestAnimationFrame के उदाहरण में ब्रेकपॉइंट सेट करना
और इसके साथ एक साथ काम नहीं करने वाली प्रोसेस चालू करें.

MutationObserver का इस्तेमाल करते समय, DOM के अपडेट को ट्रैक करना

MutationObserver की मदद से, हम DOM में होने वाले बदलावों को देख सकते हैं. इस साधारण उदाहरण में, बटन पर क्लिक करने पर, <div class="rows"></div> में एक नया डीओएम नोड जोड़ा जाता है.

demo.html में nodeAdded() (लाइन 31) में ब्रेकपॉइंट जोड़ें. असाइन किए गए कॉल स्टैक चालू होने पर, अब कॉल स्टैक को addNode() से शुरुआती क्लिक इवेंट पर वापस लाया जा सकता है.

पहले
बिना असाइन कॉल स्टैक के, mutationObserver के उदाहरण में ब्रेकपॉइंट सेट किया गया.
कॉल स्टैक पैनल, एसिंक्रोनस कॉल बिना चालू किया गया.
इसके बाद
असिंक्रोनस कॉल स्टैक के साथ, mutationObserver के उदाहरण में ब्रेकपॉइंट सेट किया गया.
और असाइनमेंट के साथ काम न करने वाली प्रोसेस चालू होने पर.

एक साथ काम नहीं करने वाले कॉल स्टैक में JavaScript को डीबग करने के बारे में सलाह

अपने फ़ंक्शन को नाम देना

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

उदाहरण के लिए, इस तरह का कोई अनाम फ़ंक्शन लें:

window.addEventListener('load', function() {
  // do something
});

और इसे कोई नाम दें, जैसे कि windowLoaded():

window.addEventListener('load', function <strong>windowLoaded</strong>(){
  // do something
});

जब लोड इवेंट ट्रिगर होगा, तो वह DevTools स्टैक ट्रेस में अपने फ़ंक्शन के नाम के साथ दिखेगा. यह नाम, "(बिना नाम वाला फ़ंक्शन)" के बजाय दिखेगा. इससे, एक नज़र में यह देखना बहुत आसान हो जाता है कि आपके स्टैक ट्रेस में क्या हो रहा है.

इससे पहले
कोई ऐसा फ़ंक्शन जिसका नाम नहीं है.
इसके बाद
नाम वाला फ़ंक्शन

आगे एक्सप्लोर करें

आपको याद दिला दें कि ये ऐसे सभी असाइनोक्रोनस कॉलबैक हैं जिनमें DevTools, कॉल का पूरा स्टैक दिखाएगा:

  • टाइमर: setTimeout() या setInterval() को शुरू करने के लिए, उस जगह पर वापस जाएं.
  • एक्सएचआर: xhr.send() को कॉल करने वाले पेज पर वापस जाएं.
  • ऐनिमेशन फ़्रेम: requestAnimationFrame को कॉल करने वाली जगह पर वापस जाएं.
  • प्रॉमिस: वह जगह वापस जाएं जहां प्रॉमिस पूरा हो चुका है.
  • Object.observe: वहां वापस जाएं जहां ऑब्ज़र्वर कॉलबैक को मूल रूप से बाउंड किया गया था.
  • MutationObservers: वह जगह देखें जहां म्यूटेशन ऑब्ज़र्वर इवेंट ट्रिगर हुआ था.
  • window.postMessage(): प्रोसेस के बीच मैसेज भेजने की सुविधा.
  • DataTransferItem.getAsString()
  • FileSystem API
  • IndexedDB
  • WebSQL
  • addEventListener() की मदद से, ज़रूरी शर्तें पूरी करने वाले DOM इवेंट: जिस जगह पर इवेंट ट्रिगर हुआ था वहां वापस जाएं. परफ़ॉर्मेंस की वजह से, सभी DOM इवेंट, असाइन किए गए कॉल स्टैक की सुविधा के लिए ज़रूरी शर्तें पूरी नहीं करते. फ़िलहाल उपलब्ध इवेंट के उदाहरणों में ये शामिल हैं: 'scroll', 'hashchange', और 'selectionchange'.
  • addEventListener() की मदद से मल्टीमीडिया इवेंट: वह जगह वापस जाएं जहां इवेंट ट्रिगर हुआ था. उपलब्ध मल्टीमीडिया इवेंट में ये शामिल हैं: ऑडियो और वीडियो इवेंट (उदाहरण के लिए, 'चलाएं', 'रोकें', 'गति बदलें'), WebRTC MediaStreamTrackList इवेंट (उदाहरण के लिए, 'addtrack', 'removetrack'), और MediaSource इवेंट (उदाहरण के लिए, 'sourceopen').

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

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