2012-11-12 32 views
37

में पाश के लिए एक के भीतर एक अतुल्यकालिक समारोह कॉलिंग मैं निम्नलिखित कोड है:जावास्क्रिप्ट

for(var i = 0; i < list.length; i++){ 
    mc_cli.get(list[i], function(err, response) { 
     do_something(i); 
    }); 
} 

mc_cli एक memcached डेटाबेस से संबंध है। जैसा कि आप कल्पना कर सकते हैं, कॉलबैक फ़ंक्शन एसिंक्रोनस है, इस प्रकार जब लूप पहले ही समाप्त हो जाता है तो इसे निष्पादित किया जा सकता है। साथ ही, इस तरह से कॉल करते समय do_something(i) यह हमेशा लूप के अंतिम मान का उपयोग करता है।

मैं इस तरह से

do_something((function(x){return x})(i)) 

में एक बंद करने के साथ करने की कोशिश की लेकिन जाहिरा तौर पर यह फिर से हमेशा पाश के लिए के सूचकांक का अंतिम मान उपयोग कर रहा है।

मैं भी तो जैसे पाश के लिए पहले एक समारोह की घोषणा करने की कोशिश की:

var create_closure = function(i) { 
    return function() { 
     return i; 
    } 
} 

और फिर बुला

do_something(create_closure(i)()) 

लेकिन फिर से सफलता नहीं मिली, वापसी मान हमेशा के अंतिम मूल्य जा रहा है के साथ पाश के लिए।

क्या कोई मुझे बता सकता है कि मैं बंद होने के साथ क्या गलत कर रहा हूं? मैंने सोचा कि मैं उन्हें समझ गया लेकिन मुझे नहीं पता कि यह क्यों काम नहीं कर रहा है।

उत्तर

68

चूंकि आप किसी सरणी के माध्यम से चल रहे हैं, तो आप आसानी से forEach का उपयोग कर सकते हैं जो सूची आइटम और कॉलबैक में अनुक्रमणिका प्रदान करता है। इटरेशन का अपना दायरा होगा।

list.forEach(function(listItem, index){ 
    mc_cli.get(listItem, function(err, response) { 
    do_something(index); 
    }); 
}); 
+1

बहुत बडी प्रत्येक चक्र में पाश बंद हो जाएगा! इस कोड ने मुझे बचाया !!! : डी – DDave

+0

@ जोसेफ आप तर्क महान लगता है। क्या आप मेरे इस हिस्से को समझा सकते हैं कृपया "इटरेशन का अपना दायरा होगा"? –

12

आप बहुत करीब थे, लेकिन आप इसे कॉलबैक अंदर डालने की बजाय get को बंद करने से पारित करना चाहिए:

function createCallback(i) { 
    return function(){ 
     do_something(i); 
    } 
} 


for(var i = 0; i < list.length; i++){ 
    mc_cli.get(list[i], createCallback(i)); 
} 
+0

धन्यवाद, यह काम करता है साथ ही साथ मैंने सही के रूप में चिह्नित किया है, लेकिन मैंने इसके बजाय उस समाधान का उपयोग किया। वैसे भी बहुत बहुत धन्यवाद! – Masiar

36

यह अतुल्यकालिक-समारोह-अंदर एक पाश प्रतिमान, और मैं आमतौर पर तत्काल-आह्वान-अज्ञात-फ़ंक्शन का उपयोग करके इसका सामना करता हूं। यह सुनिश्चित करता है कि एसिंक्रोनस फ़ंक्शंस को इंडेक्स वैरिएबल के सही मान के साथ बुलाया जाता है।

ठीक है, बढ़िया। तो सभी एसिंक्रोनस फ़ंक्शन शुरू हो गए हैं, और लूप निकलता है। अब, कोई फर्क नहीं पड़ता कि ये कार्य पूरा हो जाएंगे, उनकी असीमित प्रकृति के कारण, या वे किस क्रम में पूरा करेंगे।

var total = parsed_result.list.length; 
var count = 0; 

for(var i = 0; i < total; i++){ 
    (function(foo){ 
     mc_cli.get(parsed_result.list[foo], function(err, response) { 
      do_something(foo); 
      count++; 
      if (count > total - 1) done(); 
     }); 
    }(i)); 
} 

// You can guarantee that this function will not be called until ALL of the 
// asynchronous functions have completed. 
function done() { 
    console.log('All data has been loaded :).'); 
} 
+0

यह थोड़ी देर हो गया है, लेकिन इसके लिए धन्यवाद। एक बड़ी समस्या हल हो गई जिसमें मैं वास्तव में सरल तरीके से था। – Raelshark

+0

अच्छा समाधान। धन्यवाद। – mile

+1

इस पर एक नाम डालने के लिए धन्यवाद: एसिंक्रोनस-फ़ंक्शन-इन-ए-लूप :) – compte14031879

7

मैं जानता हूँ कि मेरा यह उत्तर जोड़ने पुराने धागा है, लेकिन वैसे भी: यदि आप कोड जब तक इन सभी कार्यों को क्रियान्वित करने से पहले पूरी कर ली है इंतजार करने की जरूरत है कि है, तो मैं कितने कार्यों समाप्त कर दिया है की एक सरल गिनती रखने की सलाह देते। ES2015 let प्रत्येक यात्रा पर पाश चर rebinding की सुविधा है, तो यह, अतुल्यकालिक कॉलबैक में पाश चर का मान रखता है ताकि आप एक नीचे की कोशिश कर सकते हैं:

for(let i = 0; i < list.length; i++){ 
    mc_cli.get(list[i], function(err, response) { 
     do_something(i); 
    }); 
} 

लेकिन वैसे भी, यह forEach उपयोग करना बेहतर है या let ईएस2015 सुविधा है और सभी ब्राउज़रों और कार्यान्वयन का समर्थन नहीं कर सकता है, इसलिए तुरंत-आवंटित-फ़ंक्शन का उपयोग करके बंद करें। here से Bindings ->let->for/for-in loop iteration scope के तहत मैं देख सकता हूं कि यह एज 13 तक और तक फ़ायरफ़ॉक्स 49 (मैंने इन ब्राउज़रों में चेक नहीं किया है) तक समर्थित नहीं है।यह भी कहता है कि यह नोड 4 के साथ समर्थित नहीं है, लेकिन मैंने व्यक्तिगत रूप से परीक्षण किया और ऐसा लगता है कि यह समर्थित है।

+0

मैं पिछले 24 घंटों के लिए दीवार पर अपने सिर को टक्कर लगी हूं, क्योंकि मुझे पता नहीं लगा कि एफ ** राजा 'लूप' के लिए क्यों काम नहीं कर रहा है। मैं इस पोस्ट को तब तक 'var i = 0' का उपयोग कर रहा हूं जब तक कि मैं आपकी पोस्ट नहीं देखता। मैं 'var i = 0' को 'i = 0'' में बदलता हूं और सब कुछ जादुई रूप से ठीक काम करता है। मैं आपको अपनी सारी प्रतिष्ठा कैसे दे सकता हूं, आप इसके लायक हैं ... –

+0

@TalhaTemuri हाहा, अच्छा है कि यह आपकी मदद करता है। – vikneshwar

0

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

var arr = ['Hello', 'World', 'Javascript', 'Async', ':)']; 
for(var i = 0; i < arr.length; i++) { 
    (function(index){ 
    setTimeout(function(){ 
     console.log(arr[index]); 
}, 500); 
0

इस प्रयास करें, async/await वाक्य रचना और Promise

(async function() { 
    for(var i = 0; i < list.length; i++){ 
     await new Promise(next => { 
      mc_cli.get(list[i], function(err, response) { 
       do_something(i); next() 
      }) 
     }) 
    } 
})() 

का उपयोग कर यह तक next() समारोह शुरू हो रहा है धन्यवाद