js引擎解析:
http://www.(搜狐)suchso.com/projecteactual/Javascript-setTimeout-timer.html
时间延迟不能被保证。什么意思,就是说你这样写setTimeout(fn, 500)并不代表fn肯定在500毫秒之后马上就执行,延迟很可能会更长。因为 JavaScript 是单线程语言,所有的异步事件(包括计时器、鼠标事件或者一个 XMLHttpRequest 完成)仅仅当程序执行期间有缺口的时候才会执行,不是你规定了什么时候就什么时候执行,要知道程序员不是万能的,你写的东西最终还是要看浏览器脸色的。
笔者注:js是一个单线程的语言,他的事件执行机制可以看成是 排队 。(这个概念是我在一个博文上阮一峰大神的博客:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html)
讲一个常问的问题,setTimeout(fn ,0 ),
这个fn不会立即执行,第一个是浏览器的更新频率限制了,第二个是js引擎的事件队列机制。
浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步.
假如某一浏览器内核的实现至少有三个常驻线 程:javascript引擎线程,界面渲染线程,浏览器事件触发线程,除些以外,也有一些执行完就终止的线程,如Http请求线程,
这些异步线程都会产生不同的异步事件,
下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的.
虽然每个浏览器内核实现细节不同,但这其中的 调用原理都是大同小异.
由图可看出,浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,
这些任务可以源自 JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,
如界面元素鼠标点击事件,定时触发 器时间到达通知,异步请求状态变更通知等.
从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线 程关系,这些任务得进行排队,一个接着一个被引擎处理.
IE8及其之前的IE版本更新间隔为15.6毫秒。假设你设定的setTimeout延迟为16.7ms,那么它要更新两个15.6毫秒才会该触发延时。这也意味着无故延迟了 15.6 x 2 - 16.7 = 14.5毫秒。 16.7ms DELAY: |------------| CLOCK: |----------|----------| 15.6ms 15.6ms 所以即使你给setTimeout设定的延时为0ms,它也不会立即触发。目前Chrome与IE9+浏览器的更新频率都为4ms(如果你使用的是笔记本电脑,并且在使用电池而非电源的模式下,为了节省资源,浏览器会将更新频率切换至于系统时间相同,也就意味着更新频率更低)。 退一步说,假使timer resolution能够达到16.7ms,它还要面临一个异步队列的问题。因为异步的关系setTimeout中的回调函数并非立即执行,而是需要加入等待队列中。但问题是,如果在等待延迟触发的过程中,有新的同步脚本需要执行,那么同步脚本不会排在timer的回调之后,而是立即执行.
延迟器setTimeout和定时器setInterval的区别
setTimeout(function(){ /* Some long block of code... */ setTimeout(arguments.callee, 10); }, 10); setInterval(function(){ /* Some long block of code... */ }, 10); 这两句代码乍一看没什么差别,但是它们是不同的。
setTimeout回调函数的执行和上一次执行之间的间隔至少有10ms(可能会更多,但不会少于10ms),而setInterval的回调函数将尝试每隔10ms执行一次,不论上次是否执行完毕。 在这里我们学到了很多知识,总结一下: JavaScript引擎是单线程的,强制所有的异步事件排队等待执行 setTimeout 和 setInterval 在执行异步代码的时候有着根本的不同 如果一个计时器setTimeout被阻塞而不能立即执行,它将延迟执行直到下一次可能执行的时间点才被执行(比期望的时间间隔要长些) 如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔