每个循环中的 settimeout 有问题

Posted

技术标签:

【中文标题】每个循环中的 settimeout 有问题【英文标题】:having issue with the settimeout in a each loop 【发布时间】:2012-09-06 01:46:18 【问题描述】:

我正在尝试循环一些以毫秒为单位的值。我需要每隔 xxxx 秒运行一些代码,具体取决于他从循环中获得的值,但我无法让它工作,它工作得很好,但它没有按时运行。

代码包含一个重置按钮(代码来自插件,但我不得不修改它)

//插件选项

  step:[
      
          time: 6000,
          // more stuff here 
          // but we dont need 
          // it in this example
      ,
      
          time: 3000,
          // more stuff here 
          // but we dont need 
          // it in this example
      ,
      
          time: 12000,
          // more stuff here 
          // but we dont need 
          // it in this example
      
  ]

// 循环

  var timeouts = [];
  $.each(options.step, function(i, value)

      var time =  value.time;                                                       
      timeouts.push(setTimeout(function()

          alert('some action');

      ,time*i));

  );

//重置按钮

  $('.stop').click(function()
      $.each(timeouts, function (_, id) 
          clearTimeout(id);
      );
      timeouts = [];
  )

【问题讨论】:

【参考方案1】:

time*i - 这可能是你的问题。

以您提供的数据为例,您会得到以下时间:6000300012000

让我们将这些乘以i,你会得到0300024000

编辑: 正如下面的 cmets 中所建议的,您希望第一个值始终为零,而结果值则保持原样。

将超时延迟设置为i == 0 ? 0 : time 会起作用。

这基本上意味着expression ? true : false;

这是一个例子:http://jsfiddle.net/2ka9g/1/

【讨论】:

只是不要乘以i。只需使用time 然后使用i == 0 ? 0 : time; 不起作用,看起来它在继续之前循环了值 2【参考方案2】:

我的主要猜测是您没有设置所需的计时器时间。您使用i * value.time 作为您的计时器时间,这看起来很奇怪。你是否意识到i 是你数组的索引,所以第一次它会是零,然后是 1,然后是 2,等等......

这将导致计时器时间为:0*6000, 1*3000, 2*12000,转换为 0, 3000, 24000

这似乎不是你想要的。

此外,浏览器中的 javascript 是单线程的(除了 webWorkers 和一些我们在这里不讨论的事件副作用)。因此,setTimeout() 不保证准确。如果在计时器事件触发时正在运行其他东西,则该计时器事件将进入事件队列,并将稍后在当前 Javascript 执行线程完成时运行。因此,setTimeout() 将不会按时运行,如果其他东西在它触发时正在运行。

【讨论】:

不完全正确。 ***.com/questions/2734025/… @BlakeRegalia - 那篇文章与上下文或 OP 的问题无关(例如 setTimeout() 的时间)。 只是说,最好不要在不承认极端情况的情况下就 JavaScript 做出粗体、笼统的陈述。感谢您编辑您的答案 @BlakeRegalia - 根据我所知道的单线程与多线程的任何定义,该文章中描述的事件触发仍然是单线程的。没有两个 javascript 执行线程同时进行。某些事件处理程序可能会因为您调用 .focus() 而运行这一事实就像一个同步函数调用。它不是多线程的。如果您的代码设计不佳并且需要注意,但仍然是单线程的,则可能会导致问题。当然,整个问题与setTimeout() 触发的时间无关。【参考方案3】:

您设置的时间间隔将为 0 秒 (6000 * 0)、3 秒 (3000 * 1) 和 24 秒 (24000 * 2)。这是因为您要乘以索引 (i)。这是您要达到的时间间隔吗?

【讨论】:

好吧,如果我只使用值它会起作用(这是我第一次使用),但现在它具有不同的值。 那么是索引器的使用导致了这个错误吗?如果没有,请指定您要通过具体间隔实现的目标。 好吧,我正在尝试每 xxx 秒运行一段代码(取决于值),如果我在上面的示例中使用固定值 10000,它将运行一段代码,然后等待继续前 10 秒,运行一段代码并等待 10 秒等。是的,我认为索引不是正确的值,也不是不同的值。 你不需要乘以索引器。删除该表达式 (time*i)。由于闭包函数作用域,您也不需要 time 变量: var timeouts = []; $.each(options.step, function(i, value) timeouts.push(setTimeout(function() alert('some action'); ,value.time)); );

以上是关于每个循环中的 settimeout 有问题的主要内容,如果未能解决你的问题,请参考以下文章

循环中的 setTimeout。如何获得正确的订单

js经典面试问题:如何让for循环中的setTimeout()函数像预想中一样工作?

按钮中的闪烁文本

循环遍历数组并一次显示单个项目,动态持续时间,如 react js 中的 setTimeout 或 SetInterval

for循环中的setTimeout()

如何为 setTimeout() 方法传参