Javascript 无延迟调用setTimeout

Javascript 无延迟调用setTimeout,javascript,settimeout,Javascript,Settimeout,在JavaScript库中经常会看到这样的代码: setTimeout(function() { ... }, 0); 我想知道为什么要使用这样的包装器代码。以允许执行任何以前设置的超时。您这样做有几个原因 有一个操作您不希望立即运行,但确实希望在不久的将来某个时间段运行 您希望允许以前从setTimeout或setInterval注册的其他处理程序运行 当您希望在不等待前一个代码完成的情况下执行其余代码时,需要将其添加到传递给setTimeout函数的匿名方法中。否则,代码将等待上

在JavaScript库中经常会看到这样的代码:

setTimeout(function() {
    ...
}, 0);

我想知道为什么要使用这样的包装器代码。

以允许执行任何以前设置的超时。

您这样做有几个原因

  • 有一个操作您不希望立即运行,但确实希望在不久的将来某个时间段运行
  • 您希望允许以前从
    setTimeout
    setInterval
    注册的其他处理程序运行

当您希望在不等待前一个代码完成的情况下执行其余代码时,需要将其添加到传递给setTimeout函数的匿名方法中。否则,代码将等待上一步完成

示例:

function callMe()
{
   for(var i = 0; i < 100000; i++)
     {
       document.title = i;
     }
} 

var x = 10;
setTimeout(callMe, 0);

var el = document.getElementById('test-id');
el.innerHTML = 'Im done before callMe method';
函数callMe()
{
对于(变量i=0;i<100000;i++)
{
document.title=i;
}
} 
var x=10;
setTimeout(callMe,0);
var el=document.getElementById('test-id');
el.innerHTML='imdone before callMe method';
这就是我使用它的原因。

非常简单:

浏览器是单线程的,这个单线程(UI线程)在渲染引擎和js引擎之间共享

如果您想做的事情需要花费大量时间(我们在这里讨论循环,但仍然如此),它可能会停止(暂停)渲染(流和绘制)

在浏览器中也存在“bucket”,所有事件都首先放入其中,等待UI线程完成它正在做的任何事情。一旦线程完成,它就会查看bucket并在队列中首先选择任务

使用
setTimeout
可以在延迟后在bucket中创建一个新任务,并让线程在可以进行更多工作时尽快处理它

故事:

延迟0毫秒后,创建函数的新任务 把它放进桶里。此时UI线程正忙着 做一些别的事情,桶里还有另一个任务 已经。6毫秒后,线程可用,并在前面获取任务 你的,很好,你是下一个。但是什么呢?那是一件大事!它有 就像以前一样(30毫秒)

最后,现在线程完成了,并且来获取您的 任务

大多数浏览器的最小延迟大于0,因此将0作为延迟意味着:尽快将此任务放入篮中。但告诉UA尽快将其放入桶中并不能保证它会在那一刻执行。水桶就像邮局一样,可能还有一长串的其他任务。邮局也是单线程的,只有一个人帮助完成所有任务。。。为客户的任务感到抱歉。你的任务必须和其他人一样

如果浏览器没有实现自己的ticker,它将使用操作系统的tick循环。旧浏览器的最小延迟为10-15毫秒。HTML5规定,如果延迟小于4ms,UA应将其增加到4ms。据说是这样

有关更多详细信息,请参见John Resig


编辑:另见2014年JSConf EU的Philip Roberts。这是所有接触前端代码的人必须查看的内容。

除了前面的答案之外,我还想添加另一个有用的场景:从try-catch块中“逃脱”。try-catch块内的setTimeout延迟将在块外执行,任何异常都将在全局范围内传播

也许是最好的示例场景:在今天的JavaScript中,对于异步回调,更常见的是所谓的延迟/承诺,您(通常)实际上是在一个try-catch中运行的。 延迟/承诺将回调封装在try-catch中,以便能够检测异常并将其作为异步链中的错误传播。这对于需要在链中的函数都是很好的,但迟早您会“完成”(即获取所有ajax)并希望运行简单的非异步代码,而您不希望异常被“隐藏”了。 AFAIK Dojo、Kris Kowal的Q、MochiKit和Google闭包库使用try-catch包装(但不是jQuery)

(在一些奇怪的情况下,我也使用了这种技术来重新启动单例代码,而不会导致递归。例如,在同一个循环中进行拆卸式重新启动)。

PRO提示:您不需要在最后使用
,0