简体   繁体   English

立即调用setTimeout

[英]Call setTimeout without delay

Quite often see in JavaScript libraries code like this: 经常在JavaScript库中看到这样的代码:

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

I would like to know why use such a wrapper code. 我想知道为什么要使用这样的包装代码。

Very simplified: 非常简化:

Browsers are single threaded and this single thread (The UI thread) is shared between the rendering engine and the js engine. 浏览器是单线程的,这个单线程(UI线程)在呈现引擎和js引擎之间共享。

If the thing you want to do takes alot of time (we talking cycles here but still) it could halt (paus) the rendering (flow and paint). 如果你想要做的事情需要很多时间(我们在这里谈论周期但仍然)它可能会停止(paus)渲染(流动和绘画)。

In browsers there also exists "The bucket" where all events are first put in wait for the UI thread to be done with whatever it´s doing. 在浏览器中还存在“存储桶”,其中所有事件首先被放入,等待UI线程完成它正在做的任何事情。 As soon as the thread is done it looks in the bucket and picks the task first in line. 一旦线程完成,它就会在存储桶中查找并首先选择任务。

Using setTimeout you create a new task in the bucket after the delay and let the thread deal with it as soon as it´s available for more work. 使用setTimeout您可以在延迟后在存储桶中创建一个新任务,并让线程在可用于更多工作时立即处理它。

A story: 一个故事:

After 0 ms delay create a new task of the function and put it in the bucket. 延迟0 ms后,创建该功能的新任务并将其放入存储桶中。 At that exact moment the UI thread is busy doing something else, and there is another tasks in the bucket already. 在那个确切的时刻,UI线程正忙于做其他事情,并且存在桶中的另一个任务。 After 6ms the thread is available and gets the task infront of yours, good, you´re next. 6毫秒后,线程可用,并在你的面前完成任务,好的,你是下一个。 But what? 但是什么? That was one huge thing! 那是一件大事! It has been like foreeeeeever (30ms)!! 它就像是上司(30ms)!!

At last, now the thread is done with that and comes and gets your task. 最后,现在线程已经完成并且来了并获得了你的任务。

Most browsers have a minimum delay that is more then 0 so putting 0 as delay means: Put this task in the basket ASAP. 大多数浏览器的最小延迟大于0,因此将0作为延迟意味着:尽快将此任务放在篮子中。 But telling the UA to put it in the bucket ASAP is no guarantee it will execute at that moment. 但是告诉UA尽快将其放入存储桶并不能保证它会在那一刻执行。 The bucket is like the post office, it could be that there is a long queue of other tasks. 这个桶就像邮局一样,可能是因为有很长的其他任务。 Post offices are also single threaded with only one person helping all the task... sorry customers with their tasks. 邮局也是单线程的,只有一个人帮助完成所有任务......抱歉客户完成任务。 Your task has to get in the line as everyone else. 你的任务必须和其他人一样。

If the browser doesn´t implement its own ticker, it uses the tick cycles of the OS. 如果浏览器没有实现自己的自动收报机,它会使用操作系统的滴答周期。 Older browsers had minimum delays between 10-15ms. 较旧的浏览器具有10-15ms之间的最小延迟。 HTML5 specifies that if delay is less then 4ms the UA should increase it to 4ms. HTML5 指定如果延迟小于4ms,则UA应将其增加到4ms。 This is said to be consistent across browsers released in 2010 and onward . 据说这在2010年及之后发布的浏览器中一致的

See How JavaScript Timers Work by John Resig for more detail. 有关详细信息,请参阅John Resig的JavaScript定时器如何工作

Edit: Also see What the heck is the event loop anyway? 编辑:另外看看事件循环到底是什么? by Philip Roberts from JSConf EU 2014. This is mandatory viewing for all people touching front-end code. 来自JSConf EU 2014的Philip Roberts。这是所有接触前端代码的人的强制性观看。

There are a couple of reasons why you would do this 为什么要这样做会有几个原因

  • There is an action you don't want to run immediately but do want to run at some near future time period. 有一个动作你不想立即运行,但希望在不久的将来某个时段运行。
  • You want to allow other previously registered handlers from a setTimeout or setInterval to run 您希望允许来自setTimeoutsetInterval其他先前注册的处理程序运行

Apart from previous answers I'd like to add another useful scenario I can think of: to "escape" from a try-catch block. 除了以前的答案,我想添加另一个我能想到的有用场景:从try-catch块中“逃脱”。 A setTimeout-delay from within a try-catch block will be executed outside the block and any exception will propagate in the global scope instead. try-catch块内的setTimeout-delay将在块外部执行,任何异常都将在全局范围内传播。

Perhaps best example scenario: In today's JavaScript, with the more common use of so called Deferreds/Promises for asynchronous callbacks you are (often) actually running inside a try-catch. 也许最好的示例场景:在今天的JavaScript中,对于异步回调所谓的Deferreds / Promises的更常见的使用,你(通常)实际上在try-catch中运行。 Deferreds/Promises wrap the callback in a try-catch to be able to detect and propagate an exception as an error in the async-chain. Deferreds / Promises将回调包装在try-catch中,以便能够在异步链中检测并传播异常作为错误。 This is all good for functions that need to be in the chain, but sooner or later you're "done" (ie fetched all your ajax) and want to run plain non-async code where you Don't want exceptions to be "hidden" anymore. 这对于需要在链中的函数来说都是有用的,但是迟早你已经“完成”(即获取所有的ajax)并且想要运行普通的非异步代码,你不希望异常“隐藏“了。 AFAIK Dojo, Kris Kowal's Q, MochiKit and Google Closure lib use try-catch wrapping (Not jQuery though). AFAIK Dojo,Kris Kowal的Q,MochiKit和Google Closure lib使用try-catch包装(尽管不是jQuery)。

(On couple of odd occasions I've also used the technique to restart singleton-style code without causing recursion. Ie doing a teardown-restart in same loop). (在几个奇怪的场合我也使用了这种技术来重启单例式代码而不会导致递归。就是在同一个循环中进行拆机 - 重启)。

When you want to execute rest of your code without waiting previous one to finish you need to add it in anonymous method passed to setTimeout function. 如果要执行其余代码而不等待前一个代码完成,则需要将其添加到传递给setTimeout函数的匿名方法中。 Otherwise your code will wait until previous is done 否则,您的代码将等到上一次完成

Example: 例:

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';

That is the reason I use it. 这就是我使用它的原因。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM