立即调用setTimeout

def*_*fuz 39 javascript settimeout

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

setTimeout(function() {
    ...
}, 0);
Run Code Online (Sandbox Code Playgroud)

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

and*_*toi 60

非常简化:

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

如果你想要做的事情需要很多时间(我们在这里谈论周期但仍然)它可能会停止(paus)渲染(流动和绘画).

在浏览器中还存在"存储桶",其中所有事件首先被放入,等待UI线程完成它正在做的任何事情.一旦线程完成,它就会在存储桶中查找并首先选择任务.

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

一个故事:

延迟0 ms后,创建该功能的新任务并将其放入存储桶中.在那个确切的时刻,UI线程正忙于做其他事情,并且存在桶中的另一个任务.6毫秒后,线程可用,并在你的面前完成任务,好的,你是下一个.但是什么?那是一件大事!它就像是上司(30ms)!!

最后,现在线程已经完成并且来了并获得了你的任务.

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

如果浏览器没有实现自己的自动收报机,它会使用操作系统的滴答周期.较旧的浏览器具有10-15ms之间的最小延迟.HTML5 指定如果延迟小于4ms,则UA应将其增加到4ms.据说这在2010年及之后发布的浏览器中一致的.

有关详细信息,请参阅John Resig的JavaScript定时器如何工作.

编辑:另外看看事件循环到底是什么?来自JSConf EU 2014的Philip Roberts.这是所有触摸前端代码的人的强制性观看.


Jar*_*Par 9

为什么要这样做会有几个原因

  • 有一个动作你不想立即运行,但希望在不久的将来某个时段运行.
  • 您希望允许其他以前注册的处理程序来自setTimeoutsetInterval运行


小智 7

除了以前的答案,我想添加另一个我能想到的有用场景:从try-catch块中"逃脱".try-catch块内的setTimeout-delay将在块外部执行,任何异常都将在全局范围内传播.

也许最好的例子场景:在今天的JavaScript,与更普遍使用了你(经常)实际上是一个try-catch内部运行的异步回调所谓Deferreds /承诺.Deferreds/Promises将回调包装在try-catch中,以便能够在异步链中检测并传播异常作为错误.这对于需要在链中的函数来说都是有用的,但是迟早你已经"完成"(即获取所有的ajax)并且想要运行普通的非异步代码,而你不希望异常"隐藏"了.AFAIK Dojo,Kris Kowal的Q,MochiKit和Google Closure lib使用try-catch包装(尽管不是jQuery).

(在几个场合奇我也用这种技术来重新启动单式的代码,而不会引起递归.即在做同样的循环中的拆解重启).


Sen*_*kin 6

当您想在不等待前一个完成的情况下执行其余代码时,您需要将其添加到传递给 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';
Run Code Online (Sandbox Code Playgroud)

这就是我使用它的原因。