फ़ायरफ़ॉक्स के नए संस्करणों में XMLHttpRequest के अजीब व्यवहार के बारे में एक जांच की कहानी

I. समस्या का सार।


XMLHttpRequest, निश्चित रूप से, मुख्य प्रयोजनों की सूची में HTML अनुरोध शामिल नहीं है, अधिक बार यह उपकरण XML, JSON या सादे पाठ के साथ इंटरैक्ट करता है।

हालांकि, XMLHttpRequest + HTML बंडल ब्राउज़र एक्सटेंशन बनाते समय अच्छी तरह से काम करता है जो पृष्ठभूमि पोल समाचार साइटों में ईमेल सदस्यता, आरएसएस या अन्य कम लागत वाले एपीआई प्रदान नहीं करता है या कुछ प्रतिबंधों के साथ इन सेवाओं को प्रदान करता है।

फ़ायरफ़ॉक्स के लिए कई एक्सटेंशन बनाते समय, मुझे ऐसी ज़रूरत आई। XMLHttpRequest से नियमित अभिव्यक्ति का उपयोग करके प्राप्त HTML कोड के साथ काम करना एक बहुत ही अविश्वसनीय और बोझिल तरीका है। आप सही XML के लिए XMLHttpRequest से DOM प्राप्त कर सकते हैं। इसलिए, मुझे डेवलपर की साइट पर मुश्किल सुझावों का पालन करना पड़ा। हालाँकि, फ़ायरफ़ॉक्स 11 के साथ शुरू करना, XMLHttpRequest से सीधे DOM को प्राप्त करना संभव हो गया, और फ़ायरफ़ॉक्स 12 में टाइमआउट प्रोसेसिंग को जोड़ा गया।

मैंने दो छोटे मंचों के लिए नए विषयों के मिनी-संकेतक बनाने पर एक नए अवसर का अनुभव किया, और यह बहुत सुविधाजनक निकला (कोड की 50 लाइनें प्लस कस्टम्सबटन एक्सटेंशन - यहां पांच मिनट में रेडीमेड संकेतक टाइमर टाइमर और चार राज्यों के साथ, कोई समाचार नहीं है, समाचार है) , त्रुटि और समय समाप्त; अधिक विवरण यहाँ पढ़ा जा सकता है )। सब कुछ घड़ी की तरह काम किया।

इसलिए, मैंने अपने एक्सटेंशन के कोड से सभी पुरानी बैसाखी को हटाने और वहां एक नया सुविधाजनक पार्सिंग पेश करने की कोशिश की। हालाँकि, जब rutracker.org वेबसाइट के साथ काम करते हैं, तो एक अजीब समस्या उत्पन्न हुई (परीक्षण Windows XP के तहत अंतिम रात में होता है; मैं कोड और भाषा में सभी गलतियों के लिए माफी माँगता हूँ: मेरे पास एक प्रोग्रामर शिक्षा नहीं है और इस क्षेत्र में मेरा अनुभव दुर्भाग्य से बहुत छोटा है; ) ..

निम्नलिखित सरलीकृत कोड उदाहरण लगभग हर समय टाइमआउट में जाता है (सत्यापन के लिए, आपको साइट पर लॉग इन करने की आवश्यकता है - फिर यह स्पष्ट हो जाएगा कि यह क्यों महत्वपूर्ण है):

var xhr = new XMLHttpRequest(); xhr.mozBackgroundRequest = true; xhr.open("GET", "http://rutracker.org/forum/index.php", true); xhr.timeout = 10000; xhr.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; xhr.responseType = "document"; xhr.onload = function() { alert(this.responseXML.title); } xhr.onerror = function() { alert("Error!"); } xhr.ontimeout = function() { alert("Timeout!"); } xhr.send(null); 


और DOM में पकड़ HTML पार्सिंग में है, क्योंकि साइट बिना देरी के पेज देती है और, उदाहरण के लिए, पार्सिंग के बिना निम्नलिखित कोड बिना किसी हिचकिचाहट के काम करता है:

 var xhr = new XMLHttpRequest(); xhr.mozBackgroundRequest = true; xhr.open("GET", "http://rutracker.org/forum/index.php", true); xhr.timeout = 10000; xhr.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; xhr.onload = function() { alert(this.responseText.match(/<title>.+?<\/title>/i)[0]); } xhr.onerror = function() { alert("Error!"); } xhr.ontimeout = function() { alert("Timeout!"); } xhr.send(null); 


XMLHttpRequest विनिर्देशन में कहा गया है कि जब DOM में HTML / XML को पार्स किया जाता है, तो परिणामी दस्तावेज़ ट्री में लिपियों को निष्पादित नहीं किया जाएगा, संदर्भित संसाधनों को लोड नहीं किया जाएगा और कोई संबद्ध XSLT लागू नहीं किया जाएगा , अर्थात स्क्रिप्ट संसाधित नहीं हैं और कोई संसाधन लोड नहीं किए गए हैं (जिसकी पुष्टि की गई है वर्णित अनुरोधों के लिए HTTP गतिविधि की निगरानी करना), इसलिए इन पक्षों पर कोई देरी नहीं हो सकती है। एकमात्र पकड़ केवल डोम की संरचना में ही हो सकती है: किसी कारण से, जमा देता है और छद्म समयबाह्य बनाता है।

द्वितीय। अतिरिक्त टिप्पणियों।


फिर मैंने DOM आँकड़ों के लिए एक छोटी स्क्रिप्ट बनाई और उसकी मदद से समस्या पृष्ठ का विश्लेषण करना शुरू किया।

 var doc = content.document; var root = doc.documentElement; var text_char = root.textContent.length; var elm_nodes = doc.evaluate(".//*", root, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength; var txt_nodes = doc.evaluate(".//text()", root, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength; var com_nodes = doc.evaluate(".//comment()", root, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength; var all_nodes = doc.evaluate(".//node()", root, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength; var max_nst_lv = 0; var max_nst_lv_nodes = 0; for (var level = 1, pattern = "./node()"; level <= 50; level++, pattern += "/node()") { var elm_num = doc.evaluate(pattern,root,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotLength; if (elm_num) { max_nst_lv = level; max_nst_lv_nodes = elm_num; } } alert( text_char + "\ttext characters\n\n" + elm_nodes + "\telement nodes\n" + txt_nodes + "\ttext nodes\n" + com_nodes + "\tcomment nodes\n" + all_nodes + "\tall nodes\n\n" + max_nst_lv_nodes + " nodes in the " + max_nst_lv + " maximum nesting level\n" ); 


यहां कुछ अधिक हैरान करने वाले आंकड़े दिए गए हैं।

1. जावास्क्रिप्ट के साथ मंच का मुख्य पृष्ठ बंद कर दिया गया है: पाठ नोड्स में 49677 वर्ण, 4192 HTML तत्व, 4285 पाठ नोड्स, 77 टिप्पणियाँ, कुल 8554 नोड्स; नोड्स के अधिकतम 25 वें घोंसले के स्तर पर 577 नोड्स।

2. यदि आप फ़ोरम से बाहर निकलते हैं और अनधिकृत उपयोगकर्ताओं के लिए पृष्ठ डाउनलोड करते हैं, तो आपको निम्न आँकड़े मिलते हैं: टेक्स्ट नोड्स में 47831 अक्षर, 3336 एचटीएमएल तत्व, 4094 टेक्स्ट नोड्स, 73 टिप्पणियाँ, कुल 7503 नोड्स; नोड्स के अधिकतम 24 वें घोंसले के स्तर पर 1136 नोड्स। संरचना स्पष्ट रूप से सरल है और यदि आप मंच को छोड़कर समस्याग्रस्त कोड की कोशिश करते हैं (जो कि अनधिकृत उपयोगकर्ताओं के लिए इस पृष्ठ पर है), तो कोई टाइमआउट नहीं होता है।

3. मैंने समस्या पृष्ठ को परीक्षण स्थल पर अपलोड करने की कोशिश की और धीरे-धीरे इसकी संरचना को सरल बनाया। उदाहरण के लिए, यदि हम वर्ग पंक्ति 1 (हेडर पेज पर तालिका में मंच और सबफ़ोर्म हेडिंग) के साथ सभी td तत्वों को हटाते हैं और कुछ और नहीं बदलते हैं, तो हमें निम्नलिखित आँकड़े मिलते हैं: पाठ नोड्स में 20,450 वर्ण, 1355 HTML तत्व, 1726 पाठ नोड्स, 77 टिप्पणियाँ, कुल 3158 नोड्स; नोड्स के अधिकतम 25 वें घोंसले के स्तर पर 8 नोड्स। और फिर, बहुत कम अपवादों वाला यह पृष्ठ टाइमआउट नहीं देता है।

4. script तत्वों का एक बहुत ही अजीब अर्थ है। शीर्षक पृष्ठ पर उनमें से 19 हैं (सिर और शरीर संयुक्त, लोड और एम्बेडेड)। यदि आप केवल इन तत्वों को हटाते हैं, तो पृष्ठ टाइमआउट देना बंद कर देता है। इसके अलावा, यदि आप शुरू से अंत तक हटाते हैं, तो आपको सब कुछ हटाने की आवश्यकता है (भले ही आप पहले भरी हुई स्क्रिप्ट को सिर में छोड़ दें, टाइमआउट)। और यदि आप शुरू से अंत तक हटाते हैं, तो "नियम, मूल निर्देश, FAQs" अनुभाग में फोरम_डेस्क p तत्व में निर्मित स्क्रिप्ट को हटाने के बाद टाइमआउट बंद हो जाता है, आप इसके बाद 6 और स्क्रिप्ट छोड़ सकते हैं, और टाइमआउट अभी भी बंद हो जाएगा (इसके अलावा, हटाने केवल यह स्क्रिप्ट समस्या का समाधान नहीं करता है)। इसके अलावा, यदि सभी 19 लिपियों को बिना कोड के खाली script तत्वों द्वारा प्रतिस्थापित किया जाता है और src विशेषता के बिना, टाइमआउट बने रहते हैं। लेकिन अगर आप इन खाली तत्वों को समान मात्रा में समान style तत्वों के साथ बदलते हैं, तो टाइमआउट तुरंत गायब हो जाते हैं।

5. PERL पर स्क्रिप्ट का उपयोग करते हुए, मैंने परीक्षण HTML को अधिक या कम जटिल संरचना (लेकिन script तत्वों के बिना) के साथ बनाने की कोशिश की। परिणाम निम्न आँकड़ों के साथ आकार में लगभग 10 मेगाबाइट की एक फ़ाइल थी: पाठ नोड्स में 9732505 वर्ण, 25004 HTML तत्व, 25002 पाठ नोड्स, 1000 टिप्पणियाँ, कुल 51006 नोड्स; नेस्टिंग के अधिकतम 27 वें स्तर पर 1000 समुद्री मील। ऐसा लगता है कि संरचना समस्या पृष्ठ की तुलना में बड़ी और अधिक जटिल है, लेकिन यह किसी भी समय समाप्ति का कारण नहीं बनती है। यह स्पष्ट हो गया कि मामला तत्वों की मात्रा / जटिलता / विशिष्टता के कुछ अस्पष्ट संयोजन में था।

6. एक को केवल इस नकली पृष्ठ पर script तत्वों को जोड़ना था, टाइमआउट लौटा (भले ही मैंने इस कठिन मामले में टाइमआउट सीमा को एक मिनट तक बढ़ा दिया)।

तृतीय। आसानी से प्रतिलिपि प्रस्तुत करने योग्य उपयोग मामला बनाना।


मैं ट्रैकर मुखपृष्ठ की संरचना के साथ तुलनीय संरचना की समस्या का एक निश्चित महत्वपूर्ण न्यूनतम हासिल करने में कामयाब रहा, जिसकी एक स्क्रिप्ट की मदद से पेरल:

 use strict; use warnings; open(OUTPUT, '>:raw:encoding(UTF-8)', "test.html") or die "Cannot write to test.html: $!\n"; print OUTPUT "<!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>\n" . "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Test</title></head><body>" . (("<div class='abcd'>abcd" x 25 . "</div>" x 25 ) x 10 . "<script type='text/javascript'>var a = 1234;</script>") x 20 . "</body></html>\n"; close(OUTPUT); 


पृष्ठ आँकड़े: पाठ नोड्स में 20,265 वर्ण, 5024 HTML तत्व, 5022 पाठ नोड्स, 0 टिप्पणियाँ, कुल 10046 नोड्स; नेस्टिंग नोड्स के अधिकतम 27 वें स्तर पर 200 नोड्स। जिसमें 20 प्राथमिक script तत्व शामिल हैं। हमें 10 प्रयासों से 10 टाइमआउट मिले।

संरचना को सरल बनाने या वॉल्यूम को कम करने के विभिन्न प्रयासों के साथ, टाइमआउट की संभावना कम हो जाती है, लेकिन एक अप्रत्याशित तरीके से (इनमें से कोई भी सरलीकरण दूसरे के साथ ओवरलैप नहीं किया जाता है, इससे पहले कि प्रत्येक स्क्रिप्ट मूल कोड पर लौट आए)

- सभी script तत्वों को कोड के अंत तक ले जाना (इस तथ्य के बावजूद कि कुछ और नहीं बदलता है और आंकड़े समान रहते हैं): 10 प्रयासों में से 0 टाइमआउट।
- एक तत्व और एक ही पाठ सामग्री के साथ span तत्वों के साथ script तत्वों की जगह (अंत तक जाने के बिना): 10 प्रयासों से 0 टाइमआउट।
- 3 अक्षरों द्वारा स्क्रिप्ट पाठ का संक्षिप्त विवरण: 10 में से 7 टाइमआउट।
- स्क्रिप्ट की पूरी सामग्री को हटाना (केवल एक खाली टैग रहता है): 10 प्रयासों में से 6 टाइमआउट।
- एक तत्व के लिए div तत्वों के पाठ की कमी: 10 प्रयासों से 5 टाइमआउट।
- div तत्वों के पाठ को हटाने (हमें एक रिक्त पृष्ठ मिलता है): 10 प्रयासों में से 7 टाइमआउट।
- एक तत्व के लिए div तत्वों की वर्ग विशेषता में कमी: 10 प्रयासों से 8 टाइमआउट।
- div तत्वों की वर्ग विशेषता को हटाना: 10 प्रयासों से 1 टाइमआउट।
- script तत्वों की संख्या को घटाकर 2 (कोड के बीच में और अंत में): फिर से 10 प्रयासों से 10 टाइमआउट।
- script तत्वों की संख्या को घटाकर 1 (कोड की शुरुआत में): 10 प्रयासों से सभी समान 10 टाइमआउट (लेकिन यदि आप इस तत्व को कोड के अंत में ले जाते हैं, तो टाइमआउट पूरी तरह से गायब हो जाते हैं)।
- घोंसले के अधिकतम स्तर को बनाए रखते हुए div तत्वों (और इसलिए टेक्स्ट नोड्स) की संख्या को आधा करना: 10 प्रयासों में से 3 टाइमआउट।
- नेस्टिंग के अधिकतम स्तर को आधे से कम करना (तत्वों और पाठ नोड्स की कुल संख्या लगभग समान रहती है, लेकिन नेस्टिंग के अधिकतम स्तर पर तत्वों की संख्या दोगुनी हो जाती है): 10 प्रयासों में से 7 टाइमआउट।
तत्वों की कुल संख्या को बनाए रखते हुए केवल 3 ( body/div/ टेक्स्ट या body/script/ टेक्स्ट) को नेस्टिंग के अधिकतम स्तर में कमी: 10 प्रयासों से 8 टाइमआउट।

चतुर्थ। प्रारंभिक निष्कर्ष।


वर्णित सभी मामलों में, कोई प्रोसेसर अधिभार नहीं देखा गया था, इसलिए हैंग के लिए हार्डवेयर को दोष देने का कोई कारण नहीं है (साथ ही नेटवर्क देरी: कोड एक दूसरे विभाजन में प्राप्त होता है, पृष्ठ ब्राउज़र में बहुत कम समय के लिए प्रदान किया जाता है)। जाहिर है, XMLHttpRequest में, डोम में HTML पार्सिंग के लिए कुछ सीमित संसाधन आवंटित किए जाते हैं, जो मापदंडों के एक अलग संयोजन द्वारा समाप्त हो जाते हैं। इसके अलावा, script तत्व (जो निष्पादित भी नहीं किए जाते हैं) और विशेष रूप से कोड में उनका क्रम एक रहस्यमय भूमिका निभाता है। यदि यह सच है, तो यह संसाधनों को बढ़ाने और तत्वों के प्रकार और क्रम पर एक अजीब निर्भरता को कम करने के लायक है, क्योंकि समस्या कोई मतलब नहीं है और दूर-दराज के सामान्य विकास के दौरान उत्पन्न होती है।

V. आगे क्या है।


जब मैं सिर्फ समस्या का विश्लेषण करना शुरू कर रहा था और कई साइटों पर सलाह मांगी, तो मंचों.mozilla.org ने एक प्रदर्शन बग का सुझाव दिया और मुझे कोर :: DOM अनुभाग में एक संदेश भेजने का सुझाव दिया जिसमें पुन: प्रस्तुत स्थिति का वर्णन किया गया था। तब मेरे पास बहुत कम डेटा था, और अब वे बहुत अस्पष्ट हैं। इसलिए, मैं किसी भी विचार के लिए आभारी रहूंगा जो हमें समस्या को निर्दिष्ट करने और स्पष्ट रूप से व्यक्त करने की अनुमति देता है। अन्यथा, आपको इस सभी शीट का अंग्रेजी में अनुवाद करना होगा (जो कि भाषा और सामग्री के ज्ञान के मेरे स्तर पर मेरे लिए बहुत मुश्किल होगा) और बगज़िला.मोज़िला.ऑर्ग पर पोस्ट करें, जो निश्चित रूप से, अन्य लोगों के समय के लिए अपमान की अभिव्यक्ति होगी।

Source: https://habr.com/ru/post/In145953/


All Articles