这不仅仅是一个问题,它是一个确保Javascript超时功能的服务质量(QoS)的请求。
查看以下伪代码:
.. start something in JS after a user action
.. some js code
setTimeout( function() { doSomething }, 1 );
.. continue for longer than 1ms doing something
.. end code for user action
.. after
.. execute doSomething
我们能确定在所有主要的浏览器上,超时代码都是在代码处理完第一个用户操作之后完成的吗?这与延迟时间无关。
延迟时间并不重要,而是"doSomething"代码在之后执行。
0延迟会发生什么?
提前感谢您在不同浏览器上的体验。
由于Javascript的单线程特性,异步事件"激发"时与实际执行时不同。
正在评估的每个代码块在内部表示为任务队列中的一个任务。因此,假设在给定代码块的中间,准备通过setTimeout()
执行异步事件。如果延迟足够短,在实践中,在同一代码块的其余部分完成执行之前,没有什么能阻止它"启动"。然而,"激发"并不意味着setTimeout
处理程序实际上会中断并执行。这只是意味着它已经变成了任务队列中的一个任务。实际执行仍然需要等待,直到它从任务队列中弹出,而这在原始代码块完成之前是不可能发生的。
这里有一个HTML5规范片段,虽然它不是所有浏览器的权威,当然是HTML5,但很有说明性:
http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#processing-型号-3
为主事件循环定义的7个步骤中的第一个是:
- 在事件循环的一个任务队列上运行最旧的任务,忽略相关文档未完全活动的任务[…]
请注意,第一步是原子步骤。该任务必须运行到完成,然后才能重置环境并拾取下一个任务。
还可以看看John Resig的帖子:http://ejohn.org/blog/how-javascript-timers-work/
所以,写下你的问题:
我们能确定在所有主要浏览器上,超时代码都是在处理第一个用户操作的代码之后完成的吗。这与延迟时间无关。
。。。答案是肯定的,我们可以肯定。(在普通的情况下……我想我们只是在谈论传统的单/UI线程,而不是Web Workers的处理)。
此外,尽管你确实提到你不太关心延迟时间本身,但你可能也有兴趣注意到"箝位时间"(强制最小延迟),它似乎事实上标准化为4ms左右。
setTimeout
依赖于实现,它不保证在指定的超时内回调。相反,您应该将timeout参数视为对底层引擎的提示,提示您希望何时回调已注册函数。如果浏览器正忙/被长时间运行的脚本卡住,回调可能会无限期延迟。当您考虑到浏览器是单线程的时,这一点就会很清楚。
简单地说,超时0表示您希望引擎在可行的情况下尽快调用已注册的函数。
通过注册超时,您只是在浏览器事件队列中预订了一个插槽。您将保证回调,但等待的持续时间由许多其他因素决定,而不仅仅是由超时值决定(尽管这是一个重要因素)。