while循环中的setTimeout()方法



我已经阅读了w3schools的相关页面和其他类似问题,但似乎无法理解以下一点有什么问题:

var myfunc03 = function (i) {
  document.getElementById('d01').innerHTML += 100-i+"<br>";
};
var myFunc01 = function() {
  i=0;
  while (i<100) {
    setTimeout(myfunc03(i), 1000)
    i++;
  }
};

运行时myFunc01();

没有任何暂停,i 的所有可能值都会立即列出。

这里有逻辑错误吗?

while循环不会等待setTimeout()完成。您需要为每个设置不同的时间延迟以不同的时间执行它们,并使用闭包来保存 i 的值。同样在您的情况下,函数将首先执行,返回值设置为setTimeout()中的参数,因此您需要在匿名函数中调用函数或直接设置函数。

var myFunc01 = function() {
  var i = 0;
  while (i < 100) {
    (function(i) {
      setTimeout(function() {
        document.getElementById('d01').innerHTML += 100 - i + "<br>";
      }, 1000 * i)
    })(i++)
  }
};
myFunc01();
<span id="d01"></span>


虽然setInterval()可以在这里使用

var myFunc01 = function() {
  var i = 0;
  // store the interval id to clear in future
  var intr = setInterval(function() {
    document.getElementById('d01').innerHTML += 100 - i + "<br>";
    // clear the interval if `i` reached 100
    if (++i == 100) clearInterval(intr);
  }, 1000)
}
myFunc01();
<span id="d01"></span>

你可以用递归更简单地做到这一点:

var i = 0;
function f1() { ... };   
function f() {
    f1();
    i += 1;
    setTimeout(function() {
        if(i < 100) {
            f();
        }
    }, 1000);
}
f();

var i = 0;
var myfunc03 = function(i) {
  document.getElementById('d01').innerHTML += 100 - i + "<br>";
};
var myFunc01 = function() {
  myfunc03(i);
  i += 1;
  setTimeout(function() {
    if (i < 100) {
      myFunc01();
    }
  }, 1000);
}
myFunc01();
<div id="d01"></div>

<小时 />

可重用函数

function say(sentence) {
  console.log(sentence);
}
function sayHello() {
  say("Hello!");
}
var fn = sayHello;
var count = 10;
var ms = 1000;
function repeat(fn, count, ms) {
  var i = 0;
  function f() {
    fn();
    i += 1;
    setTimeout(function() {
      if (i < count) {
        f();
      }
    }, ms);
  }
  f();
}
repeat(fn, count, ms);

while等待setTimeout

(async () => {
  var i = 0;
  while (await new Promise(resolve => setTimeout(() => resolve(i++), 1000)) < 100) {
    console.log("I get printed 100 times every second");
  }
})();

您可以创建超时函数并将其与async/await一起使用

// Timeout function
const timeout = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// Run some loop in async function
(async () => {
  // Loop for 5 times
  for(let i = 0; i <= 5; i++) {
    // Do some stuff
    console.log(`Some stuff ${i}`);
    // Wait for timeout 1000 ms
    await timeout(1000);
  }
})();

是的。代码中有 2 个问题:

  1. setTimeout 函数接受函数作为第一个参数,但在代码中,myfunc03(i)不返回任何内容
  2. while 循环不能满足您的需求,相反,您必须使用递归函数。因为第二个函数应该在第一个超时触发后调用。

示例代码:

var myfunc03 = function (i) {
  setTimeout(function() {
    document.getElementById('d01').innerHTML += 100-i+"<br>";
    if (i < 100) {
      i++;
      myfunc03(i);
    }
  }, 1000);
};
var myFunc01 = function() {
  myfunc03(0);
};
myFunc01();
<div id="d01"></div>

  • 我认为您在 setTimeout 上缺少一个分号,您应该尝试以以下方式传递参数:

    setTimeout(myfunc03, 1000*i, i); 
    
一个简单的

选择是改用setInterval()方法。setInterval 每次都会将代码作为循环执行,直到您使用 clearInterval() 方法中断它。

示例

var index = 0;
let incrementEveryHalfSecond = setInterval(function(){
  index++;
  document.querySelector("body").innerHTML += index+'</br>';
  if(index == 10) clearInterval(incrementEveryHalfSecond)
}, 500) 
<body></body>

观察您决定中断循环,将存储 setInterval 方法的变量作为参数传递到 clearInterval 方法中。现在,您可以创建函数来获得更好的明代码。W3学校文档

问答:[从100到1]为了简化,我颠倒了i的顺序,但你也可以用"100-i

"。

var myfunc03 = function (i) {
  document.getElementById('d01').innerHTML += i+"<br>";
};
var myFunc01 = function() {
  let i=100;
  let incrementEveryOneSecond = setInterval(function(){
    myfunc03(i);
    if(--i == 0) clearInterval(incrementEveryOneSecond);
  }, 1000) 
 
};
myFunc01();
 <span id="d01"></span>

while方法运行速度很快,所有超时几乎在第一秒后执行。 你能做的是

  1. 而不是 while 从 myfunc03 调用 $timeout 以获取下一个值
  2. 在您的 while 调用超时中,像i*1000一样增加秒

此外,正如其他人指出的那样,您不能使用setTimeout这样的参数调用函数使用匿名函数,例如

...
while (i<100) {
  setTimeout(
     function(i){
        myfunc03(i);
     }, i*1000);
   i++;
}
...

为此

最新更新