2012-03-22 25 views
9

मेरे पास एक घटना है, जो खुद को आग लग सकती है। मैं कोड को यथासंभव कुशल बनाने की कोशिश करता हूं, लेकिन यह कुछ परिस्थितियों में अधिकतम कॉल स्टैक को मार सकता है, जो मेरे नियंत्रण से बाहर हैं। यह एक अनंत ढेर नहीं है और यह किसी बिंदु पर समाप्त हो जाएगा, लेकिन कभी-कभी यह सीमा के कारण खत्म होने से पहले संभावित रूप से क्रैश कर सकता है।जावास्क्रिप्ट में अधिकतम कॉल स्टैक कैसे बढ़ाएं?

यदि मैं 2 समान ईवेंट श्रोताओं को सेट करता हूं और कोड को विभाजित करता हूं तो क्या मैं कॉल स्टैक की संख्या बढ़ा दूंगा? या मैं क्या कर सकता हूँ?

अद्यतन: यह डीओएम परिवर्तन घटना (केवल वेबकिट के साथ काम करना, इसलिए अन्य ब्राउज़रों के बारे में परवाह नहीं है) पर है, जो कुछ स्थितियों के आधार पर डीओएम को भी संशोधित कर सकता है। मैंने अभी तक उस सीमा को वास्तव में नहीं मारा है, लेकिन सिद्धांत रूप से, यह संभावित रूप से कर सकता है। मैं अभी भी जितना संभव हो उतना कम डोम मैनिप्लेशंस बनाने के लिए कोड को अनुकूलित कर रहा हूं।

अद्यतन 2: मैं नमूना शामिल कर रहा हूँ (नहीं असली) उदाहरण:

document.addEventListener('DOMSubtreeModified', function(event){ 

    this.applyPolicy(event); 

}, true); 

function applyPolicy(event){ 
    if(typeof event != "undefined"){ 
     event.stopPropagation(); 
     event.stopImmediatePropagation(); 
    } 

    if(!isButtonAllowed){ 
     $('button:not(:disabled)').each(function(){ 

      $(this).attr('disabled', true); 

     }); 
    } 
} 

यह सिर्फ एक नमूना कोड है, लेकिन फिर भी इस मामले में, बटन के 100s कहना जब आपके पास, कॉल ढेर 100 में भी होगा। ध्यान दें कि यदि आप $('button').attr('disabled', true); का उपयोग करते हैं, तो यह कॉल स्टैक समस्या का कारण बन जाएगा, क्योंकि jQuery डीओएम को असीमित रूप से संशोधित करने का प्रयास करेगा।

+1

शायद आपको अपने रिकर्सिव फ़ंक्शन को '' जबकि 'लूप में परिवर्तित करना चाहिए? मैं कल्पना नहीं कर सकता कि आपको कुछ अन्य फ़ंक्शन को आग लगाने के लिए वास्तविक सैकड़ों हजारों ईवेंट ट्रिगर्स के दुष्प्रभाव की आवश्यकता है ... –

+1

कभी भी उस सीमा तक नहीं पहुंचा, अगर ग़लत रूप से अनंत-लूप को कोडिंग नहीं किया जाता है। कोड दिखाएं .. – gpasci

+2

संक्षिप्त उत्तर: ऐसा करने के लिए कोई (मानक) तंत्र नहीं है। तब एकमात्र विकल्प कोड को बदलना है। –

उत्तर

6

हालांकि ऐसा लगता है कि आपको कुछ कोड पर पुनर्विचार करने की आवश्यकता हो सकती है, एक संभावना है कि किसी दिए गए अंतराल पर setTimeout में एक रिकर्सिव कॉल डालना होगा। यह आपको एक नया कॉल स्टैक शुरू करने की अनुमति देता है।

इस उदाहरण लें ...

var i = 0; 

function start() { 
    ++i; 
    var is_thousand = !(i % 1000); 

    if (is_thousand) 
     console.log(i); 

    if (i >= 100000) 
     return; // safety halt at 100,000 
    else 
     start() 
} 

यह सिर्फ 1,000 के हर अंतराल पर कंसोल के लिए लॉग करता है। क्रोम में यह 30,000 रेंज में कहीं भी ढेर से अधिक है।

डेमो:http://jsfiddle.net/X44rk/


लेकिन आप इसे इस तरह फिर से काम करता है, तो ...

var i = 0; 

function start() { 
    ++i; 
    var is_thousand = !(i % 1000); 

    if (is_thousand) 
     console.log(i); 

    if (i >= 100000) // safety halt at 100,000 
     return; 
    else if (is_thousand) 
     setTimeout(start, 0); 
    else 
     start(); 
} 

अब हर 1,000 पर, समारोह वापस जाने के लिए अनुमति दी जाएगी और अगले एक नया कॉल स्टैक शुरू करने के साथ कॉल को असीमित रूप से बनाया जाएगा।

ध्यान दें कि यह मानता है कि रिकर्सिव कॉल किए जाने पर फ़ंक्शन प्रभावी रूप से समाप्त हो जाता है।

यह भी ध्यान दें कि मेरे पास 100,000 पर रुकने की शर्त है इसलिए हम अनंत नहीं हैं।

डेमो:http://jsfiddle.net/X44rk/1/

+0

यह दिलचस्प लग रहा है। मैं इसे एक शॉट दूँगा। धन्यवाद! – Sherzod

+0

@ शेरशम्स: आपका स्वागत है। यदि तुम्हारे सवाल हों तो मुझे बताओ। –

+1

मैंने लाखों रिकर्सन के साथ आपके कोड की कोशिश की, यह अभी भी ठीक काम करता है। मैं अभी इस तकनीक का उपयोग कर अपना कोड कार्यान्वित कर रहा हूं। धन्यवाद! – Sherzod

6

किसी भी ब्राउज़र के लिए अधिकतम कॉल स्टैक हजारों में अच्छी तरह से चलता है। आपको कोड को अनुकूलित करने का प्रयास करना चाहिए, जिसमें एक विशाल कॉल स्टैक होना गति और स्मृति के लिए अच्छा नहीं है।

आप इस में चल रहे हैं, यह एक संकेत के अपने कोड पुनर्गठन

+0

बात यह है कि, घटना डीओएम परिवर्तन के लिए सुन रही है, और कुछ स्थितियों की जांच करने के बाद, यह वास्तव में डीओएम को संशोधित कर सकती है, जो उस घटना को दोबारा आग लग जाएगी। इसके कारण, कॉल स्टैक बहुत तेजी से बढ़ सकता है। मैं अभी भी जितना संभव हो उतना कम डोम मैनिप्लेशंस बनाने के लिए कोड को अनुकूलित करने पर काम कर रहा हूं। – Sherzod

+0

ठीक है, यह एक बहुत ही सामान्य टिप्पणी है जिसे मैं जानता हूं .. लेकिन आपको चिंताओं का एक स्पष्ट अलगाव की आवश्यकता है। यदि आप डोमचेंज घटनाओं को सुनते हैं, तो इसका मतलब है कि आप अपने डीओएम पर 'मॉडल' या 'व्यू मॉडल' के रूप में भरोसा करते हैं। इसके साथ कुछ गलत चीजें हैं। Backbone.js को लागू करने का प्रयास करें, भले ही आप इसे विशेष रूप से पसंद न करें .. आप अच्छे यूआई डिज़ाइन पैटर्न से एक बड़ा सौदा सीख सकते हैं। – Evert

+0

मैं जावास्क्रिप्ट एमवीसी और jQuery का उपयोग कर रहा हूं। इस मामले में रिकर्सन को कम करने का एकमात्र तरीका डीओएम मैनिप्लेशंस की संख्या को कम करना है, ताकि वह खुद को इतनी बार आग न सके .. क्या कोई बेहतर तरीका है? – Sherzod

0

callstack और कार्यान्वयन विवरण के आकार की सख्त जरूरत जावास्क्रिप्ट वातावरण अपने कोड में चल रहा है पर निर्भर करेगा में है। यहां तक ​​कि आप अगर उन परिवेशों में चलाने के लिए स्टैक उपयोग में हेरफेर कर सकते हैं जिनकी आप परवाह करते हैं, वहां एक शानदार मौका है कि एक ऐसे स्टैक-भूखे कोड को एक ऐसे वातावरण में चलाया जाता है जो एक अलग स्टैक आकार प्रदान करता है।

कोई भी पुनरावर्ती कार्यक्रम पुनरावर्तक के रूप में पुनः लिखा जा सकता है। विचार करें कि क्या आप अपने मामले में ऐसा कर सकते हैं। देखें:

Way to go from recursion to iteration

0

आप कर सकते हैं नहीं, वे ब्राउज़र निर्भर कर रहे हैं और काफी स्पष्ट रूप से वे काफी एक विस्तृत श्रृंखला है, इसलिए इस बारे में IMO में चिंता करने की कोई जरूरत नहीं।

0

यदि आप कॉल स्टैक सीमा को मार रहे हैं, तो आप लगभग निश्चित रूप से घटनाओं की एक पुनरावर्ती श्रृंखला है। घटनाएं एक ढेर पर भरोसा करती हैं, इसलिए वे वास्तव में एक लूप को लागू करने का सबसे अच्छा तरीका नहीं हैं। पूंछ कॉल उन्मूलन के बिना एक भाषा में, आपका एकमात्र असली विकल्प मानक लूप संरचनाओं का उपयोग करना है जैसे कि/इन।

0

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

  1. एक छिपा iframe में अपने डोम डुप्लिकेट:

    ऐसी है कि कोई तृतीय-पक्ष कोड की उम्मीद है (या दिया जाता है) अपने कोड rearchitecting डोम के लिए उपयोग के बाहर

    , मेरे समाधान के रूप में निम्नानुसार होगा।

  2. सैंडबॉक्स ने कहा कि iframe में तीसरे पक्ष कोड।
  3. आईफ्रेम में किसी भी डोम परिवर्तन पर, दो डोम पेड़ के बीच अंतर के लिए आईफ्रेम का निरीक्षण करें। यदि परिवर्तन श्वेतसूची पास करता है, तो इसे अपने वास्तविक डोम (फिर से अटैचिंग ईवेंट कॉलबैक और अन्य) में खींचें।
  4. आईफ्रेम डीओएम में अपडेट के बाद "वास्तविक" डोम की संरचना की प्रतिलिपि बनाएँ, प्रक्रिया में किसी भी संवेदनशील डेटा को स्क्रब करना।

आप अभी भी आईफ़्रेम में एक डोम ईवेंट की जांच करेंगे, लेकिन आप अपने "वास्तविक" पृष्ठ में नहीं होंगे, इसलिए आप एक अनंत लूप दर्ज नहीं कर सकते हैं।

यह मानते हुए कि आप वास्तव में नहीं कर सकते हैं कि ऐसा करने के लिए अपने तीसरे पक्ष कोड पर भरोसा करें। अगर यह सिर्फ विक्रेता अक्षमता है, तो स्क्रबिंग हिस्से को भूल जाओ, लेकिन ब्लैकलिस्ट की बजाय श्वेतसूची के साथ चिपके रहें, वैसे भी।

+0

प्रकाशन से पहले कोड को स्वयं एक अलग स्क्रिप्ट द्वारा विश्लेषण किया जाता है, लेकिन तीसरे पक्ष के डेवलपर कुछ घटनाओं पर कुछ चीजों को अक्षम करने के लिए भूल गए हैं, इसलिए, मुझे इसे जांचना और उस नीति को लागू करना होगा। मैं निश्चित रूप से आपके द्वारा उल्लिखित विधि का उपयोग करके कुछ सरल बनाने की कोशिश करूंगा। Iframes का विचार दिलचस्प लगता है, हालांकि मैं उन्हें नफरत करता हूं। धन्यवाद! – Sherzod

संबंधित मुद्दे