setTimeout和setInterval
Javascript是单线程语言,设置有setTimeout和setInterval两个计数器,其中setTimeout是超时调用,setInterval是间歇调用。
setTimeout()超时调用是指在指定时间之后执行代码。超时调用使用window对象的setTimeout()方法,它接受两个参数:第一个参数可以是要执行的函数也可以是要计算的表达式,第二个参数是要等待执行代码的时间,以毫秒表示。后面接受的参数表示为要执行的函数要接受的参数。setTimeout() 只执行 code 一次。如果要多次调用,可以使用 setInterval() 或者让 code 自身再次调用 setTimeout()。
<!doctype html> <html> <head> <script> setTimeout(myfunc,2000); function myfunc(){ document.write("hello"); } </script> </head> <body > </body> </html>
上面的代码在页面刷新之后会在两秒之后页面输出“hello”;但是要注意的是setTimeout函数的第二个参数是执行代码要等待的时间,但是有的情况它并不一定会执行,这是因为JavaScript是一个单线程序的解释器,因此一定时间内只能执行一段代码。为了控制要执行的代码,就有一个JavaScript任务队列。这些任务会按照将它们添加到任务队列的顺序执行。setTimeout()的第二个参数告诉JavaScript再过多长时间把当前任务添加到队列中。如果队列是空的,那么添加的代码则会立即执行;如果队列不是空的,那么添加的代码会在前面的代码执行完毕后再执行。
调用setTimeout()之后,该方法会返回一个数值ID,表示超时调用。这个超时调用ID是计划执行代码的唯一标识符,可以通过它来取消超时调用。取消超时调用使用方法clearTimeout()。
<!doctype html> <html> <head> <script> var timeId = setTimeout(myfunc,2000); function myfunc(){ document.write("hello"); } clearTimeout(timeId); </script> </head> <body > </body> </html>
上面的代码页面刷新之后就不会出现“hello”。
setInterval()间歇调用是指按照指定的时间间隔重复执行代码,直至间歇调用被取消或页面被卸载。设置间歇调用的方法是setInterval(),它接收的参数与setTimeout()相同。setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。如上面setTimeout一样。
<!doctype html> <html> <head> <script> var timeId = setInterval(myfunc,2000); function myfunc(){ document.write("hello"); } </script> </head> <body > </body> </html>
上面的页面在被刷新之后页面每两秒就会向页面写一个“hello”。但是通常情况下,很少真正使用间歇调用,因为后一个间歇调用可能在前一个间歇调用结束之前调用。因此,我们通常会使用超时调用来模拟间歇调用。即在超时调用函数里面执行超时调用。
最后来说一下setTimeout和setInterval的运行机制。
setTimeout和setInterval的运行机制是,将指定的代码移出本次执行,等到下一轮事件循环时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮事件循环时重新判断。这就是说,setTimeout指定的代码,必须等到本次执行的所有代码都执行完,才会执行。
每一轮事件循环时,都会将“任务队列”中需要执行的任务,一次执行完。setTimeout和setInterval都是把任务添加到“任务队列”的尾部。因 此,它们实际上要等到当前脚本的所有同步任务执行完,然后再等到本次事件循环p的“任务队列”的所有任务执行完,才会开始执行。由于前面的任务到底需要多少时间执行完,是不确定的,所以没有办法保证,setTimeout和 setInterval指定的任务,一定会按照预定时间执行。
最最后一个问题,setTimeout的作用是将代码推迟到指定时间执行,如果指定时间为0,即setTimeout(f,0),那么会立刻执行吗?
答案是不会。因为setTimeout运行机制说过,必须要等到当前脚本的同步任务和“任务队列”中已有的事 件,全部处理完以后,才会执行setTimeout指定的任务。也就是说,setTimeout的真正作用是,在“任务队列”的现有事件的后面再添加一个 事件,规定在指定时间执行某段代码。setTimeout添加的事件,会在下一次Event Loop执行。
setTimeout(f,0)将第二个参数设为0,作用是让f在现有的任务(脚本的同步任务和“任务队列”中已有的事件)一结束就立刻执行。也就是说,setTimeout(f,0)的作用是,尽可能早地执行指定的任务。
另一方面,根据HTML5标准,setTimeOut推迟执行的时间,最少是4毫秒。如果小于这个值,会被自动增加到4。这是为了防止多个setTimeout(f,0)语句连续执行,造成性能问题。