2010-05-24 14 views
31

मैं XMLHttpRequest का उपयोग कर रहा हूं, और मैं सफलता कॉलबैक फ़ंक्शन में स्थानीय चर का उपयोग करना चाहता हूं।जावास्क्रिप्ट कॉलबैक को कैसे व्यवस्थित करें ताकि फ़ंक्शन स्कोप ठीक से बनाए रखा जा सके

यहाँ कोड है:

function getFileContents(filePath, callbackFn) { 
    var xhr = new XMLHttpRequest(); 
    xhr.onreadystatechange = function() { 
     if (xhr.readyState == 4) { 
      callbackFn(xhr.responseText); 
     } 
    } 
    xhr.open("GET", chrome.extension.getURL(filePath), true); 
    xhr.send(); 
} 

और मैं इसे इस तरह कॉल करना चाहते हैं:

var test = "lol"; 

getFileContents("hello.js", function(data) { 
    alert(test); 
}); 

यहाँ, test कॉलबैक फ़ंक्शन के दायरे से बाहर हो सकता है, केवल संलग्नित के बाद से फ़ंक्शन के चर कॉलबैक फ़ंक्शन के अंदर पहुंच योग्य हैं। test को कॉलबैक फ़ंक्शन पर पास करने का सबसे अच्छा तरीका क्या है alert(test);test सही ढंग से प्रदर्शित करेगा?

संपादित करें:

अब, मैं निम्नलिखित कोड समारोह ऊपर परिभाषित बुला अगर:

for (var test in testers) { 
    getFileContents("hello.js", function(data) { 
     alert(test); 
    }); 
} 

alert(test); कोड केवल for पाश से test का अंतिम मान प्रिंट करता है। मैं इसे कैसे बना सकता हूं ताकि यह test के मान को उस समय के दौरान प्रिंट करता है जिस पर फ़ंक्शन getFileContents कहा जाता था? (मैं getFileContents बदल रहा है, क्योंकि यह एक बहुत ही सामान्य सहायक समारोह है और मैं इसे करने के लिए test की तरह एक विशिष्ट चर पारित करके यह विशिष्ट बनाने के लिए नहीं करना चाहते हैं के बिना यह कर करना चाहते हैं।

+0

यह भी देखें: http://stackoverflow.com/questions/tagged/javascript+closures+loops – CMS

उत्तर

39

आपके द्वारा प्रदान किए गए कोड के साथ test अभी भी कॉलबैक के अंदर गुंजाइश में होगा। xhrxhr.responseText के अलावा data के रूप में पारित नहीं किया जाएगा।

टिप्पणी से अपडेट किया गया:

अपने कोड मान लिया जाये कि इस तरह दिखता है:

for (var test in testers) 
    getFileContents("hello"+test+".js", function(data) { 
    alert(test); 
    }); 
} 

इस स्क्रिप्ट चलाता है के रूप में, test में testers कुंजी के मूल्यों आवंटित किया जाएगा - getFileContents प्रत्येक कहा जाता है समय, जो पृष्ठभूमि में एक अनुरोध शुरू करता है। जैसे ही अनुरोध समाप्त होता है, यह कॉलबैक को कॉल करता है। test में लूप से अंतिम VALUE शामिल होने जा रहा है, क्योंकि उस लूप ने पहले ही निष्पादन समाप्त कर दिया है।

ऐसी तकनीक है जिसका उपयोग आप बंद करने के लिए कर सकते हैं जो इस तरह की समस्या को ठीक करेगा।

for (var test in testers) { 
    getFileContents("hello"+test+".js", 
    (function(test) { // lets create a function who has a single argument "test" 
     // inside this function test will refer to the functions argument 
     return function(data) { 
     // test still refers to the closure functions argument 
     alert(test); 
     }; 
    })(test) // immediately call the closure with the current value of test 
); 
} 

यह मूलतः (हमारी नई समारोह के साथ) एक नई गुंजाइश पैदा करेगा कि "पर पकड़" होगा: आप एक नया गुंजाइश आप के साथ अपने चर पर पकड़ कर सकते हैं बनाने, एक समारोह अपने कॉलबैक फ़ंक्शन बना सकते हैं test के मूल्य के लिए।

बात का एक ही प्रकार का लेखन का एक अन्य तरीका:

for (var test in testers) { 
    (function(test) { // lets create a function who has a single argument "test" 
    // inside this function test will refer to the functions argument 
    // not the var test from the loop above 
    getFileContents("hello"+test+".js", function(data) { 
     // test still refers to the closure functions argument 
     alert(test); 
    }); 
    })(test); // immediately call the closure with the value of `test` from `testers` 
} 
+0

यदि कोड का पहला ब्लॉक किसी अन्य .js फ़ाइल में है, तो

7

जावास्क्रिप्ट lexical scoping, जो मूल रूप से इसका मतलब है कि का उपयोग करता है अपने दूसरी कोड उदाहरण की तरह है आप कैसे यह काम करना चाहते हैं काम करेंगे

निम्न उदाहरण, डेविड फ्लानागन के से उधार Definitive Guide पर विचार करें:।

var x = "global"; 

function f() { 
    var x = "local"; 
    function g() { alert(x); } 
    g(); 
} 

f(); // Calling this function displays "local" 

यह भी ध्यान में रखना टी सी, सी ++ और जावा के विपरीत टोपी, जावास्क्रिप्ट में ब्लॉक-स्तरीय दायरा नहीं है।


डेविड फ्लानागन: JavaScript - The Definitive Guide, चौथा संस्करण

इसके अलावा, आप भी निम्न आलेख, जो मैं अत्यधिक की सलाह देते हैं बाहर की जाँच में रुचि हो सकती , पृष्ठ 48.

2

इस परिदृश्य में, परीक्षण के रूप में आप इसकी अपेक्षा का समाधान हो जाएगा, लेकिन this का मूल्य अलग हो सकता है।

function getFileContents(filePath, callbackFn, scope) { 
    var xhr = new XMLHttpRequest(); 
    xhr.onreadystatechange = function() { 
     if (xhr.readyState == 4) { 
      callbackFn.call(scope, xhr.responseText); 
     } 
    } 
    xhr.open("GET", chrome.extension.getURL(filePath), true); 
    xhr.send(); 
} 


//then to call it: 
var test = "lol"; 

getFileContents("hello.js", function(data) { 
    alert(test); 
}, this); 
+0

और मैं 'getFileContents' फ़ंक्शन को कैसे कॉल करूं? – Chetan

0

मैं एक ऐसी ही समस्या का सामना किया: आम तौर पर, गुंजाइश बनाए रखने के लिए, आप इसे तो जैसे अतुल्यकालिक समारोह के लिए एक पैरामीटर होगा। मेरा कोड इस तरह दिखता था:

for (var i=0; i<textFilesObj.length; i++) 
{ 
    var xmlHttp=new XMLHttpRequest(); 
    var name = "compile/" + textFilesObj[i].fileName; 
    var content = textFilesObj[i].content; 

    xmlHttp.onreadystatechange=function() 
    { 
     if(xmlHttp.readyState==4) 
     { 
      var responseText = xmlHttp.responseText; 
      Debug(responseText); 
     } 
    } 

    xmlHttp.open("POST","save1.php",true); 
    xmlHttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); 
    xmlHttp.send("filename="+name+"&text="+encodeURIComponent(content)); 
} 

आउटपुट अक्सर अंतिम वस्तु (लेकिन हमेशा नहीं) का प्रतिक्रिया पाठ था। असल में यह यादृच्छिक था और प्रतिक्रियाओं की संख्या भी भिन्न थी (निरंतर इनपुट के लिए)। ऐसा लगता है कि समारोह में लिखा गया है चाहिए:

xmlHttp.onreadystatechange=function() 
    { 
     if(this.readyState==4) 
     { 
      var responseText = this.responseText; 
      Debug(responseText); 
     } 
    } 

मूल रूप से, पहले संस्करण में, "XMLHTTP" वस्तु संस्करण के लिए लूप के वर्तमान चरण में सेट हो जाता है। अधिकांश AJAX अनुरोध समाप्त होने से पहले लूप समाप्त हो गया था, इसलिए इस मामले में "xmlHttp" लूप के अंतिम उदाहरण को संदर्भित करता है। यदि यह अंतिम अनुरोध अन्य अनुरोधों से पहले समाप्त हो गया है तो वे सभी जब भी तैयार राज्य बदलते हैं तो अंतिम अनुरोध से प्रतिक्रिया प्रिंट करेंगे (भले ही उनके तैयार राज्य < 4 थे)।

समाधान "xmlHttp" को "इस" के साथ प्रतिस्थापित करना है ताकि आंतरिक कार्य कॉलबैक कहलाए जाने पर अनुरोध ऑब्जेक्ट के सही उदाहरण का जिक्र कर रहा हो।

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

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