setTimeout()无法更改间隔

时间:2018-04-16 21:08:24

标签: javascript jquery

我有一个test课程,background-color我希望在limegreen之间更快更快地翻转。

为此,我使用for循环变量并将其传递给包含setTimeout()的函数,但它不起作用。

(这不是一个重复的问题。所说的"原文"是一个简单的setTimeout(),而这个问题是关于for循环中的setTimeout()。我明白这个问题的答案可能会间接回答我的问题,但问题本身并不相同)



$(document).ready(function() {

  for (var i = 0; i < 20; i++) {
    delay(i);
    $(".test").css('background-color', 'lime');
  }

});

function delay(i) {
  setTimeout(function() {
    $(".test").css('background-color', 'green');
  }, 1000 - 50 * i);
}
&#13;
.test {
  width: 300px;
  height: 300px
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test"></div>
&#13;
&#13;
&#13;

6 个答案:

答案 0 :(得分:1)

问题是循环执行速度超过超时。 setTimeout函数基本上表示在一定时间后执行给定的函数。你在那里创建的for循环将继续,而不是等待setTimeout函数内的代码被执行,换句话说,你的代码产生了将在未来执行的20个函数。

有很多方法可以生成您需要的功能。 为了保持简单并解决它,你应该创建两个函数:

$(document).ready(function() {

  for (var i = 0; i < 20; i++) {
    delay_lime(i);
    delay_green(i+1);
  }

});

function delay_green(i) {
  setTimeout(function() {
    $(".test").css('background-color', 'green');
  }, 1000 - 50 * i);
}

function delay_lime(i) {
  setTimeout(function() {
    $(".test").css('background-color', 'lime');
  }, 1000 - 50 * i);
}

答案 1 :(得分:1)

尝试这种方式:

for(var i=0;i<20;i++)
{
  delay(i);
}

function delay(i) {
  setTimeout(function() {
      if (i%2 == 0) {
        $(".test").css('background-color', 'green');      
      } else {
        $(".test").css('background-color', 'lime');
      }

  }, 1000 - 50 * i);
}

答案 2 :(得分:1)

试试这个:这是一个例子example

$(document).ready(function() {

  delay();

  var start = 0;

   delay(start);

   function delay(start) {

       setTimeout(function() {

           if(start == 0 ){
              $(".test").css('background-color', 'green');
              start = 1;
            }else{
               $(".test").css('background-color', 'red');
                start = 0;
            }

           delay(start);

        }, 100);
    }

});

答案 3 :(得分:0)

如果您想使用for循环,则应将其包含的函数转换为async函数,并在所需时间解析await个承诺:

const delay = (i) => new Promise(resolve => {
  setTimeout(resolve, 1000 - 50 * i);
});
function changeToGreen() {
  $(".test").css('background-color', 'green');
}
function changeToLime() {
  $(".test").css('background-color', 'lime');
}
(async () => {
  for (var i = 0; i < 20; i++) {
    await delay(i);
    changeToLime();
    await delay(i);
    changeToGreen();
  }
})();

答案 4 :(得分:0)

你的循环不会等待任何超时发生,它会运行并排队以相关间隔触发的事件。

然而,在这样做时,它会将背景颜色设置为灰色多次。

循环结束后,排队的间隔开始触发,并将背景颜色设置为绿色多次。

但是颜色不会交替,因为代码执行不符合您的预期。

此外,对setInterval的多次调用将在指定的延迟之后对要触发的事件进行排队。代码不会等待分配的时间,然后触发下一个。所以你的1000 - 50 *我实际上可以先排队最新的事件,依此类推,直到排队实际上先发射的事件为止。那有意义吗?您可以更直观地按照它们将触发的顺序设置它们。您可以通过将超时增加一个减少的变量来实现减少延迟,例如

time = 1000;
delay = 1000;
setTimeout (blah, time);
time += delay;
delay -= 50;
setTimeout (blah, time);
// etc.

您可以通过将备用间隔设置为绿色和石灰来实现交替效果。为此,一个简单的切换变量会有所帮助。

color = 1;

color = 1 - color; // toggles between 0 and 1
useColor = ["lime", "green"][color];

我没有为您重写整个程序,但如果您有具体问题,我可以提供更多帮助。学习的最佳方式是做。

答案 5 :(得分:0)

对示例代码中超时的工作方式存在轻微的误解。超时是异步的,这意味着它们执行超出正常的执行顺序。结果,立即显示柠檬绿,然后在不同时间后,背景重复变为绿色;虽然,唯一一次注意到变化是第一次从绿色变为绿色没有效果。

setTimeout创建一个任务,浏览器中的JavaScript是单线程的,并将通过任务调度程序执行任务。

在问题中显示的方法中使用0到19之间的1000 - 50 * i将导致计划执行超时。首先是1000,然后是950,等等。但是,它们都安排在同一时间。因此,以正向或反向顺序排列它们没有区别,因为使用的唯一相关度量是时间。基本上结果是每50毫秒,在这个例子中背景颜色设置为绿色。

不幸的是,在浏览器中执行的任务没有准确执行,并且使用它将针对每次调用50毫秒,但由于操作系统调度并且取决于使用的系统,结果可能会大不相同。

这可以用一个间隔来完成,其中使用的间隔是50毫秒(尽管它仍然会受到上述OS问题的影响)。也就是说,那里没有使用加速。这里有一个更好的方法,因为我们处理动画(颜色闪烁)将改为使用 requestAnimationFrame MDN

requestAnimationFrame将尝试以每秒60帧的速度运行您的代码,或者每帧大约16.6毫秒(1000毫秒/ 60帧)。

鉴于目标是加速,可以采取措施来加速闪光。

&#13;
&#13;
// Cache the constructed jQuery object for element with class "test"
var testCache = $('.test');

// Create a set of colors to use in the flashing
var colors = ['lime','green'];

// Use a variable for a switch between the two colors
var colorSwitch = 0;

// Keep track of how many times the color has flashed
var i = 0;

// Used for tracking the start of an animation sequence
var start;

// In order to facilitate acceleration, use a function for 
// determining the time between flashes,
// used an offset x^2 line at (20,16) with a 2x width
// y = 1/2(x-19)^2 - 19x + 16
var ft = t => 0.5*(t-19)*(t-19) - (t-19) + 16;

// This function will be called every 16.6 milliseconds
// by requestAnimationFrame, the timestamp is automatically injected
(function flashAccel(timestamp){

 // Loop control to ensure only 20 flashes occur
 if(i >= 20) return;

 // Track the start of the timing for the animation sequence
 start = start || timestamp;

 // This is the milliseconds since the last sequence was updated
 var elapsed = timestamp - start;

 // Check to see if enough time has elapsed based on the acceleration 
 // function's value and the current value, if it has then update the view
 if( elapsed > ft(i) ){
 
     // Swaps between 0 and 1
     colorSwitch = 1 - colorSwitch;

     // Selects 0 or 1 indexed color
     var color = colors[colorSwitch];
     testCache.css('background-color',color);

     // Update metrics
     i++;
     start = timestamp;
 }

 // Request the function to be called again in roughly 16.6 milliseconds
 window.requestAnimationFrame(flashAccel);

})()
&#13;
.test {
  width: 300px;
  height: 300px
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test"></div>
&#13;
&#13;
&#13;