发布网友 发布时间:2023-09-13 14:54
共1个回答
热心网友 时间:2024-08-19 04:34
通常它们的表现行为并不是那么地直观,而这是因为它们都处在一个单一线程中。让我们先来看一看三个用来创建以及操作timer的函数。var id = setTimeout(fn, delay);- 初始化一个单一的timer,这个timer将会在一定延时后去调用指定的函数。这个函数(setTimeout)将返回一个唯一的ID,我们可以通过这个ID来取消timer。var id = setInterval(fn, delay);- 与setTimeout类似,只不过它会持续地调用指定的函数(每次都有一个延时),直到timer被取消为止。clearInterval(id);,clearTimeout(id);- 接受一个timer的ID(由上述的两个函数返回的),并且停止timer的回调事件。(点击查看大图)由于JavaScript向来都只能在同一时间执行一块代码(这是由它单线程的本质决定的),所以每一个代码块都阻塞了其他的异步事件。这意味着当异步事件发生时(比如鼠标点击、timer触发或者是XMLHttpRequest完成),这些事件将进入到一个队列中等待执行(队列的实现方法因浏览器而异,我们在此只讨论一个简化的情况)。刚开始,在第一个JavaScript块中,有两个timer被初始化了:一个10ms的setTimeout和一个是10ms的setInterval。由于timer(这里的timer指setTimeout中的timer,而下文中的interval则指setInvertal中的timer)开始的时间,实际上它在第一个代码块结束前就已经触发了。然而请注意,它并不会马上执行(事实上由于单线程的存在,它也无法做到马上执行)。相反的,这个被延期执行的函数进入队列中,等待在空闲的时候被执行。当第一个JavaScript块被执行完之后,浏览器问了一个问题:有正在等待被执行的代码吗?在这个例子中,鼠标点击事件和time事件都正在队列中等待。于是浏览器选了一个(鼠标点击事件),然后马上执行它。而timer只能继续等下去。注意当鼠标点击事件正在执行的时候第一次的interval事件也触发了,与timer一样,它的事件也进入队列等待之后执行。然而,注意,当interval再次触发的时候(这个时候timer的事件正在执行),这一次它的事件被丢弃了。如果你在一个大的JavaScript代码块正在执行的时候把所有的interval回调函数都囤起来的话,其结果就是在JavaScript代码块执行完了之后会有一堆的interval事件被执行,而执行过程中不会有间隔。因此,取代的作法是浏览器情愿先等一等,以确保在一个interval进入队列的时候队列中没有别的interval。让我们来看一个例子,这个例子更好地阐释了setTimeout和setInveral之间的区别。setTimeout(function(){/* 一个很长的代码块 */setTimeout(arguments.callee,10);},10);我们在此学到了很多,让我们重述一下:JavaScript引擎只有一个线程,这使得异步事件必需列队等待执行。setTimeout和如果一个timer在将要执行的时候被阻塞,它将会等待下一个时机(比预期的延时要长)。