2017-03-23 22 views
0

私は、async/ajax呼び出しの周りにループをラップするときにIIFEメソッドを実装しています。Javascript forループ関数閉鎖の印刷

私がconsole.log cntrを実行すると、すべての値が得られますが、ランダムな順序が問題になります。 forループが0-4からあるとしましょう。 2,1,3,4,0のように、これらの値はランダムな順序で出力されます。これは、コードを再実行するたびに変わります。

編集: 最も確かにリンクされている質問は答えではありません。重複としてマーキングする前に、より注意を払ってください。私もnodejを使っていません...

+3

「asyncCall」は何ですか? –

+0

私はFacebookのAPIを使用していますが、必ずしも質問に関連するものではありません。非同期呼び出しであった可能性があります。 –

+0

'asyncCall'にランダムな遅延がある場合 - あなたの場合のように乱数を得るべきです。それを動作させるために、私はChain Promise –

答えて

0

あなたのasyncCallは一定の時間内に終了しません。同期for-loop内で各非同期呼び出しを開始するので、最初に終了した呼び出しが最初にログに記録されます(つまり、呼び出しはお互いに待たない)。

この問題を解決する方法は2通りあります。最初は、あなたが再帰で簡単に行うことができた、次の開始前に完了するために、各asyncCallを待つことです。

var calls = 4 
 
var i = 0 
 

 
asyncCall(function handler() { 
 
    console.log(i) 
 
    if (++i < calls) asyncCall(handler) 
 
}) 
 

 

 
function asyncCall(handler) { 
 
    setTimeout(handler, 0) 
 
}

それぞれの連続した呼び出しが結果に依存している場合、このアプローチは、最も理にかなっています前の呼び出しのうち、あなたのものではない可能性があります。その場合には、あなたが一度呼び出しが完了したログの配列で結果を各呼び出しはアップフロント実行していますが、保存するために、より効率的である:

var calls = 4 
 
var done = 0 
 
var i = 0 
 

 
var results = [] 
 

 
for (var i = 0; i < calls; i++) (function(i) { 
 
    asyncCall(function handler() { 
 
    results[i] = i // example data 
 
    if (++done === calls) complete() 
 
    }) 
 
})(i) 
 

 
function complete() { 
 
    // Do something with your array of results 
 
    results.map(function (e) { 
 
    console.log(e) 
 
    }) 
 
} 
 

 

 
function asyncCall(handler) { 
 
    setTimeout(handler, Math.random()*10) 
 
}

0

自己実行あなたが探しているように見えた、近くには、次のように使用されます。

//<![CDATA[ 
 
/* external.js */ 
 
var doc, bod, htm, C, T, E; // for use onload elsewhere 
 
addEventListener('load', function(){ 
 

 
doc = document; bod = doc.body; htm = doc.documentElement; 
 
C = function(tag){ 
 
    return doc.createElement(tag); 
 
} 
 
T = function T(tag){ 
 
    return doc.getElementsByTagName(tag); 
 
} 
 
E = function(id){ 
 
    return doc.getElementById(id); 
 
} 
 
addClassName = function(element, className){ 
 
    var rx = new RegExp('^(.+\s)*'+className+'(\s.+)*$'); 
 
    if(!element.className.match(rx)){ 
 
    element.className += ' '+className; 
 
    } 
 
    return element.className; 
 
} 
 
removeClassName = function(element, className){ 
 
    element.className = element.className.replace(new RegExp('\s?'+className), ''); 
 
    return element.className; 
 
} 
 
var outs = doc.getElementsByClassName('output'); 
 
for(var i=0,out,l=outs.length; i<l; i++){ 
 
    (function(){ 
 
    var out = outs[i], b = false; 
 
    out.onclick = function(){ 
 
     if(b){ 
 
     removeClassName(out, 'blue'); b = false; 
 
     } 
 
     else{ 
 
     addClassName(out, 'blue'); b = true; 
 
     } 
 
    } 
 
    }()); 
 
} 
 

 
}); // close load 
 
//]]>
/* external.css */ 
 
html,body{ 
 
    padding:0; margin:0; 
 
} 
 
.main{ 
 
    width:980px; margin:0 auto; 
 
} 
 
.output{ 
 
    width:100px; border:1px solid #000; border-top:0; 
 
} 
 
.output:first-child{ 
 
    border-top:1px solid #000; 
 
} 
 
.blue{ 
 
    background:lightblue; 
 
}
<!DOCTYPE html> 
 
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'> 
 
    <head> 
 
    <meta http-equiv='content-type' content='text/html;charset=utf-8' /> 
 
    <link type='text/css' rel='stylesheet' href='external.css' /> 
 
    <script type='text/javascript' src='external.js'></script> 
 
    </head> 
 
<body> 
 
    <div class='main'> 
 
    <div class='output'>Sorry</div> 
 
    <div class='output'>This</div> 
 
    <div class='output'>Example</div> 
 
    <div class='output'>Isn&#039;t</div> 
 
    <div class='output'>Better</div> 
 
    </div> 
 
</body> 
 
</html>

閉鎖の仕組みは次のとおりです。イベントはonclickのように実際に発生します。イベントが発生する頃には、実際にループが終了しています。そのとき、変数と引数は、最後にスコープされたレベルを探します。