Javascript for循环函数关闭打印乱序

时间:2017-03-23 07:19:24

标签: javascript closures

我正在围绕异步/ ajax调用包装for循环时实现IIFE方法。

var j = 4;
for (var i = 0; i < j; i++) {
    (function(cntr) {
        asyncCall(function() {
            console.log(cntr);
        });
    })(i);
}

问题是当我在console.log cntr时,我得到了所有的值,但它们有一个随机的顺序。我们假设我有0-4的for循环。它将以随机顺序打印这些值,如2,1,3,4,0。每次重新运行代码时,这都会改变。

编辑: 最肯定的问题不是答案。在标记为重复之前请多加注意。我甚至没有使用nodejs ......

2 个答案:

答案 0 :(得分:0)

你的asyncCall没有在一段时间内完成。由于您在同步for循环中开始每个异步调用,因此首先完成的调用将首先记录(换句话说,调用不会彼此等待)。

有两种方法可以解决此问题。第一个是等待每个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)
}

答案 1 :(得分: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一样。当事件触发时你实际上是在循环结束时,所以当发生这种情况时,变量和参数会查找它们最后确定范围的级别。