2013-10-07 3 views
5

मेरे पास एक बहुत ही मामूली सवाल है। setTimeout के साथ एक सरल पाश, इस तरह के लिए:जावास्क्रिप्ट में लूप के साथ setTimeout

for (var count = 0; count < 3; count++) { 
    setTimeout(function() { 
     alert("Count = " + count); 
    }, 1000 * count); 
} 

कंसोल इस तरह एक आउटपुट देता है:

Count = 3 
Count = 3 
Count = 3 

सुनिश्चित नहीं हैं कि क्यों इस तरह उत्पादन। कोई भी समझा सकता है, कृपया?

+2

के संभावित डुप्लिकेट [पासिंग एक लूप में सेटटाइम सेट करने के लिए फ़ंक्शन: हमेशा अंतिम मान?] (http://stackoverflow.com/questions/6425062/passing-functions-to-settimeout-in-a-loop-always-the-last-value) – Quentin

उत्तर

5

यह जावास्क्रिप्ट में स्कॉइंग और होस्टिंग का इलाज कैसे किया जा रहा है इसके साथ करना है।

क्या अपने कोड में होता है कि जे एस इंजन इस के लिए अपने कोड को संशोधित करता है:

var count; 

for (count = 0; count < 3; count++) { 
    setTimeout(function() { 
     alert("Count = " + count); 
    }, 1000 * count); 
} 

और जब setTimeout() चलाया जा रहा है यह पहली बार count के बाद उसके अपने दायरे में दिखेगा, लेकिन यह इसे खोजने नहीं होगा तो यह setTimeout फ़ंक्शन पर var count कथन को तब तक बंद करने वाले कार्यों को देखना शुरू कर देगा (इसे closures कहा जाता है) जब तक यह var count कथन नहीं पाता है, जिसमें मान 3 होगा, क्योंकि लूप पहले टाइमआउट फ़ंक्शन निष्पादित होने से पहले समाप्त हो जाएगा।

अधिक कोड-ily समझाया अपने कोड वास्तव में इस तरह दिखता है:

//first iteration 
var count = 0; //this is 1 because of count++ in your for loop. 

for (count = 0; count < 3; count++) { 
    setTimeout(function() { 
     alert("Count = " + 1); 
    }, 1000 * 1); 
} 
count = count + 1; //count = 1 

//second iteration 
var count = 1; 

for (count = 0; count < 3; count++) { 
    setTimeout(function() { 
     alert("Count = " + 2); 
    }, 1000 * 2); 
} 
count = count + 1; //count = 2 

//third iteration 
var count = 2; 

for (count = 0; count < 3; count++) { 
    setTimeout(function() { 
     alert("Count = " + 3); 
    }, 1000 * 3); 
} 
count = count + 1; //count = 3 

//after 1000 ms 
window.setTimeout(alert(count)); 
//after 2000 ms 
window.setTimeout(alert(count)); 
//after 3000 ms 
window.setTimeout(alert(count)); 
1

इसके बारे में सोचो:

  1. कोड एक पाश कार्यान्वित करता है, कि पाश में इसे बाद में चलाने के लिए कुछ कोड सेट।
  2. लूप खत्म होता है।
  3. सेटटाइम कोड निष्पादित करता है। गिनती का मूल्य क्या होगा? लूप उम्र पहले समाप्त हो गया था ...
1

यह क्लोजर स्कोपिंग के साथ करना है। एक ही चर count सेटटाइमआउट कॉलबैक फ़ंक्शंस के प्रत्येक दायरे में उपलब्ध है। आप इसके मूल्य में वृद्धि कर रहे हैं और एक फ़ंक्शन बना रहे हैं, लेकिन फ़ंक्शन के प्रत्येक उदाहरण में एक ही चर count है, और जब तक कॉलबैक फ़ंक्शन निष्पादित करता है तो उसके पास मूल्य 3.

आपको एक प्रतिलिपि बनाने की आवश्यकता है इस काम को करने के लिए for लूप में एक नए दायरे के अंदर परिवर्तनीय (उदाहरण के लिए var localCount = count)। for एक गुंजाइश नहीं बनाता है (जो पूरी चीज का कारण है) आपको फ़ंक्शन स्कोप के साथ एक पेश करने की आवश्यकता है।

उदा।

for (var i = 0; i < 5; i++) { 
    (function() { 
    var j = i; 
    setTimeout(function() { 
     console.log(j) 
    }, 
    j*100); 
    })(); 
} 
+0

नहीं काम नहीं करता: 'के लिए (var i = 0; i <5; i ++) { var j = i; सेटटाइमआउट (फ़ंक्शन() { console.log (j) }, जे * 100); } ' – rofrol

+0

ऐसा इसलिए है क्योंकि 'जे' चर को मूल दायरे में फेंक दिया जाता है क्योंकि लूप एक नहीं बनाता है। आपको 'j'' को अलग करने के लिए एक नया फ़ंक्शन स्कोप बनाना होगा: '(var i = 0; i <5; i ++) {(function() {var j = i; setTimeout (function() {console.log (j)}, जे * 100);})()} ' – Joe

+0

मैंने आपके प्रश्न के जवाब में अपना प्रश्न संपादित किया। – Joe

0

क्योंकि सभी समय समाप्ति चलाए जा रहे हैं जब पाश समाप्त हो गया है यही कारण है कि।

टाइमआउट फ़ंक्शन तब गिनती का वर्तमान मूल्य लेते हैं।

और यह हमेशा 3 है क्योंकि लूप समाप्त हो गया है।

0

ऐसा इसलिए है क्योंकि जब तक लूप इसके निष्पादन को पूरा करता है तो गणना 3 होती है, और फिर सेट टाइमआउट कहा जाता है।कर रहे हैं से अधिक के बाद 1000 * n मिलीसेकंड

, क्या गिनती का मूल्य हो जाएगा:

var count = 0; 
setTimeout(function() { 
     for (count = 0; count < 3; count++) { 
      alert("Count = " + count); 
     } 
}, 1000* count); 
3

इसके बारे में इस तरह लगता है:

इस प्रयास करें?

बेशक यह 3 होगा, क्योंकि फूर लूप 1000 * एन एमएस के समय से पहले समाप्त हो गया था।

क्रम में 1,2,3 मुद्रित करने के लिए आप निम्न की आवश्यकता होगी:

for (var count = 0; count < 3; count++) { 
    do_alert(num); 
} 

function do_alert(num) { 
    setTimeout(function() { 
     alert("Count = " + num); 
    }, 1000 * num); 
} 

एक अलग दृष्टिकोण यह एक closure function (JavaScript closures vs. anonymous functions में अच्छी तरह से समझाया गया है) बनाने के लिए

for (var count = 0; count < 3; count++) { 
    (function(num){setTimeout(function() { 
     alert("Count = " + num); 
    }, 1000 * num)})(count); 
} 

इन है दो कोड नमूने वास्तव में समान रूप से काम करेंगे।

पहला नमूना प्रत्येक पुनरावृत्ति नामित फ़ंक्शन (do_alert) को कॉल करता है।

दूसरा नमूना क्लोजर अज्ञात फ़ंक्शन (जो कि do_alert जैसा है) प्रत्येक पुनरावृत्ति को कॉल करता है।

यह सब स्कोप का मामला है।

उम्मीद है कि मदद करता है।

0

बेहतर समाधान मौजूद है इस मामले में "दोनों लूप्स और Recursion भूल जाओ" और "setInterval" भी शामिल है "setTimeOut" एस के इस संयोजन का उपयोग करें:

function iAsk(lvl){ 
     var i=0; 
     var intr =setInterval(function(){ // start the loop 
      i++; // increment it 
      if(i>lvl){ // check if the end round reached. 
       clearInterval(intr); 
       return; 
      } 
      setTimeout(function(){ 
       $(".imag").prop("src",pPng); // do first bla bla bla after 50 millisecond 
      },50); 
      setTimeout(function(){ 
       // do another bla bla bla after 100 millisecond. 
       seq[i-1]=(Math.ceil(Math.random()*4)).toString(); 
       $("#hh").after('<br>'+i + ' : rand= '+(Math.ceil(Math.random()*4)).toString()+' > '+seq[i-1]); 
       $("#d"+seq[i-1]).prop("src",pGif); 
       var d =document.getElementById('aud'); 
       d.play();     
      },100); 
      setTimeout(function(){ 
       // keep adding bla bla bla till you done :) 
       $("#d"+seq[i-1]).prop("src",pPng); 
      },900); 
     },1000); // loop waiting time must be >= 900 (biggest timeOut for inside actions) 
    } 

पुनश्च: समझ लें कि (setTimeOut के वास्तविक व्यवहार): वे सभी एक ही समय में शुरू हो जाएंगे "तीन ब्ला ब्ला ब्ला एक ही पल में गिनना शुरू कर देंगे" इसलिए निष्पादन की व्यवस्था करने के लिए एक अलग टाइमआउट करें।

पी एस 2: समय पाश के लिए उदाहरण के लिए, लेकिन एक प्रतिक्रिया के लिए आप की घटनाओं का उपयोग कर सकते लूप होता है, async का इंतजार वादा ..

0

आसान यहाँ ठीक ES6 let स्थानीय चर का उपयोग करने के लिए है। आपका कोड यह सिवाय तरह ही दिखाई देगा कि आप क्या उम्मीद करेंगे :)

for (let count = 0; count < 3; count++) { 
    setTimeout(function() { 
     alert("Count = " + count); 
    }, 1000 * count); 

} 

या आप एक पुनरावर्ती समारोह बना सकते हैं कि नौकरी के निम्नलिखित के रूप में, किया जाना:

function timedAlert(n) { 
    if (n < 3) { 
    setTimeout(function() { 
     alert("Count = " + n); 
     timedAlert(++n); 
    }, 1000); 
    } 
} 

timedAlert(0); 
संबंधित मुद्दे