无延迟调用setTimeout

发布于 2024-12-31 21:50:00 字数 125 浏览 2 评论 0原文

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

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

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

Quite often see in JavaScript libraries code like this:

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

I would like to know why use such a wrapper code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浮生未歇 2025-01-07 21:50:00

非常简单:

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

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

在浏览器中还存在“存储桶”,其中所有事件首先等待 UI 线程完成其正在执行的操作。一旦线程完成,它就会在桶中查找并选择队列中第一个任务。

使用setTimeout,您可以在延迟后在存储桶中创建一个新任务,并让线程在可用于更多工作时立即处理它。

一个故事:

0毫秒延迟后创建函数的新任务
并将其放入桶中。就在那一刻,UI 线程正忙
正在做其他事情,并且桶中还有其他任务
已经。 6ms 后线程可用并获取前面的任务
你的,很好,下一个就是你了。但什么?那是一件大事!它有
就像 foreeeeeever (30ms)!!

最后,现在线程已经完成了,并得到了你的
任务。

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

如果浏览器没有实现自己的代码,它将使用操作系统的时钟周期。较旧的浏览器的最小延迟在 10-15 毫秒之间。 HTML5 指定小于 4ms,UA 应将其增加到 4ms。据说这是在 2010 年及以后发布的浏览器中保持一致

有关更多详细信息,请参阅 John Resig 撰写的 JavaScript 计时器工作原理

编辑:另请参阅事件循环到底是什么? 由 JSConf EU 2014 的 Philip Roberts 撰写。这是所有接触前端代码的人都必须查看的内容。

Very simplified:

Browsers are single threaded and this single thread (The UI thread) is shared between the rendering engine and the js engine.

If the thing you want to do takes a lot of time (we talking cycles here but still) it could halt (pause) the rendering (flow and paint).

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. 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.

A story:

After 0 ms delay create a new task of the function
and put it in the bucket. At that exact moment the UI thread is busy
doing something else, and there is another tasks in the bucket
already. After 6ms the thread is available and gets the task in front
of yours, good, you’re next. But what? That was one huge thing! It has
been like foreeeeeever (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 than 0 so putting 0 as delay means: Put this task in the basket ASAP. But telling the UA to put it in the bucket ASAP is no guarantee it will execute at that moment. 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. HTML5 specifies that if delay is less then 4ms the UA should increase it to 4ms. This is said to be consistent across browsers released in 2010 and onward.

See How JavaScript Timers Work by John Resig for more detail.

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.

九八野马 2025-01-07 21:50:00

您这样做的原因有几个:

  • 有一个操作您不想立即运行,但确实希望在不久的将来的某个时间段运行。
  • 您希望允许之前通过 setTimeoutsetInterval 注册的处理程序运行

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
北音执念 2025-01-07 21:50:00

当您想要执行其余代码而不等待前一个代码完成时,您需要将其添加到传递给 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';

这就是我使用它的原因。

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. 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.

︶葆Ⅱㄣ 2025-01-07 21:50:00

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

也许是最好的示例场景:在今天的 JavaScript 中,随着所谓的 Deferreds/Promises 更常见地用于异步回调,您(通常)实际上是在 try-catch 中运行。
Deferreds/Promises 将回调包装在 try-catch 中,以便能够检测异常并将其作为异步链中的错误传播。这对于需要在链中的函数来说都是有好处的,但是迟早你会“完成”(即获取所有的ajax)并且想要运行普通的非异步代码,而你不希望出现异常“不再隐藏”。
AFAIK Dojo、Kris Kowal 的 Q、MochiKit 和 Google Closure lib 使用 try-catch 包装(尽管不是 jQuery)。

(在一些奇怪的情况下,我还使用了该技术来重新启动单例样式代码而不引起递归。即在同一循环中进行拆卸重新启动)。

Apart from previous answers I'd like to add another useful scenario I can think of: to "escape" from a try-catch block. 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.

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.
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. This is all good for functions that need to be in the chain, but sooner or later you're "done" (i.e fetched all your ajax) and want to run plain non-async code where you Don't want exceptions to be "hidden" anymore.
AFAIK Dojo, Kris Kowal's Q, MochiKit and Google Closure lib use try-catch wrapping (Not jQuery though).

(On couple of odd occasions I've also used the technique to restart singleton-style code without causing recursion. I.e doing a teardown-restart in same loop).

不打扰别人 2025-01-07 21:50:00

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

To allow any previously set timeouts to execute.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文