【问题标题】:Are equal timeouts executed in order in Javascript?在Javascript中是否按顺序执行相等的超时?
【发布时间】:2009-11-21 18:08:17
【问题描述】:

假设我这样做

setTimeout(foo, 0);

...

setTimeout(bar, 0);

我能确定 foo 会在 bar 之前开始执行吗?如果我对 bar 使用 1、10 或 100 的超时而不是 0,该怎么办?

简单的实验表明,在超时值相等的情况下,超时目标的执行顺序与 setTimeouts 本身的顺序相同,但是依赖这种行为是否安全?

【问题讨论】:

标签: javascript settimeout operator-precedence


【解决方案1】:

依赖这种行为是不安全的。我编写了一个测试脚本,它使用 setTimeout(..., 0) 调度了许多函数(它们反过来也调度了许多函数),并且 调用函数的顺序并不总是与调用 setTimeout 的顺序相同(至少在我用来运行脚本的 Chrome 11 中)。

您可以在此处查看/运行脚本:http://jsfiddle.net/se9Jn/ (脚本使用 YUI 来实现跨浏览器兼容性,但 Y.later 在内部使用 setTimeout)。

请注意,如果您只是运行脚本并盯着控制台,您可能不会看到有问题的命令。但是如果启动脚本,切换到另一个选项卡,加载一些页面,然后返回测试页面,您应该会在控制台中看到有关回调乱序的错误。

如果您需要有保证的排序,我建议在上一个函数的末尾安排下一个函数:

setTimeout(foo, 0);

...

function foo() {

    ...

    setTimeout(bar, 0);
}

【讨论】:

    【解决方案2】:

    我通读了 Firefox 源代码,至少对于那个浏览器,有一个按非递减顺序指定的超时顺序保证。否则,所有赌注都将被取消。

    具体来说,如果在给定的执行上下文中为 n 设置超时,然后为 m 设置一个超时,其中 n

    但不要相信我的话。我相信窗口实现在 nsGlobalWindow.cpp 中,实际决定超时在执行队列中的位置的方法称为InsertTimeoutIntoList。看起来该方法向后遍历队列,寻找小于或等于给定超时的第一个超时,并在其后插入给定的超时。

    当然,当设置超时时,当前时钟时间会添加到超时值中。这就是为什么要按顺序执行目标,超时值必须是非递减顺序的原因。

    【讨论】:

      【解决方案3】:

      答案是:不,不保证执行顺序。我偶尔会在 chrome 40 中看到非 FIFO 排序,尤其是当我在调试器中暂停而超时未决时。我在野外也有过罕见的目击事件 - 这是我调查的事件的唯一合理解释。

      如果您需要保证执行顺序,您可以这样做,而不是 setTimeout(callback, 0)

      var queue = [];
      function handleQueue() {
          queue.shift()();
      }
      function queueCallback(callback) {
         queue.push(callback);
         setTimeout(handleQueue, 0);
      }
      

      现在,对于保证foobar 的订单,您可以:

      queueCallback(foo);
      ...
      queueCallback(bar);
      

      【讨论】:

      • 这将如何保证 setTimeout 的顺序而不是仅仅拥有一堆 setTimeout(action, 0)
      【解决方案4】:

      简而言之,不要指望它。看看this

      这里面有很多信息 图消化但理解它 完全会给你一个更好的 如何实现异步 JavaScript 执行有效。

      【讨论】:

      • 我在那篇文章中没有看到任何严格的要点。问题不在于目标函数何时执行,而在于它们执行的顺序。
      • 不要指望严格的顺序,这就是前面文章中“异步”的意义。
      • 当然,实际的延迟可能比预期的要长,并且间隔的工作方式与计时器不同,但本文没有直接解决这个问题。不管foo执行需要0毫秒还是100年,会不会总是发生在bar之前?还是浏览器可以随意挑选?我觉得这方面必须有一个标准(或至少一些信息)。
      【解决方案5】:

      实际延迟有一定的最小值,这在很大程度上取决于操作系统、浏览器、浏览器活动和计算机负载。我倾向于不低于 20 毫秒,因为我认为任何小于 20 毫秒的时间都没有任何区别。

      当你放置两个相等的延迟时,并不一定意味着它会按那个顺序发生。

      如果您想确保按顺序完成,我倾向于这样做:

      setTimeout(function() { 
        foo();
        setTimeout(bar, 20)
      }, 20);
      

      这将始终保证订单。

      如果您使用的是 Firefox,为了确保您的 javascript 实际上是多线程的,您可能需要查看 WebWorker,它支持较新的浏览器,但不支持 IE。

      【讨论】:

      • 你知道一个具体的例子,其中相等的超时被乱序执行吗?
      • 我只是不相信在重要的时候依赖它,因为我没有看到任何可以保证它的东西。
      • “最短”有用延迟将取决于实现和计算机速度,但“0”是用于 setTimeout 的有用时间,因为它将调用延迟到当前调用堆栈清除。跨度>
      • 我对零的唯一问题是,如果其他人正在阅读代码,它可能会给人一种立即执行的印象。
      猜你喜欢
      • 2018-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-21
      • 1970-01-01
      相关资源
      最近更新 更多