天天看点

关于setInterval()和setTimeout()一些小总结1.JavaScript的单线程模型2.setInterval()3.setTimeout()

 网页编写中常常会遇到使用定时器或者说是计时器的时候,中秋的阿里月饼事件闹得沸沸扬扬。网上有据说是本人贴出来的代码,代码中也是应用了setInterval()计时器,通过获取控件,设定计时器,来实现秒抢月饼的。当然,网上的代码不一定是阿里员工的,但利用计时器的原理应该是一样的。

1.JavaScript的单线程模型

在说setInterval之前,先来了解一下JavaScript的单线程模型。JavaScript运行在浏览器中,单线程的处理它的任务队列,这些任务可能包括一些普通函数和回调函数。当有异步事件发生时,比如鼠标点击事件发生、定时器触发事件发生、ajax请求完成回调触发等,js会将这些事件放入执行队列,等当前代码执行完毕后,再去处理队列中的事件。下面我们通过一个例子来进一步了解js的单线程。

function handleClick(){
    {耗时6ms}
}
function f(){
    {耗时3ms的操作4}
}
function init(){
    {耗时5ms的操作1}
    触发click事件
    {耗时10ms的操作2}
    setInterval(f,10);
    {耗时5ms的操作3}
}
           

那么现在我们来分析一下这个代码,首先运行init函数,操作1耗时5ms,接着触发click事件,由于单线程所以handleClick被放入执行队列中,然后操作2耗时10ms,接着触发计时器操作,由于当前还有任务在执行,所以计时器操作也被放入执行队列,最后执行操作3。

总结一下就是:

0-20ms:运行init函数

20-26ms:运行handleClick()函数

26-29ms:运行f,也就是setInterval,setInterval在15ms时被触发,由于setInterval的设置每10ms运行一次f,也就是在25ms,35ms,45ms,55ms等时候运行。但是当25ms时,js线程正在处理handleClick函数,所以被延迟到26ms,也就是handleClick函数执行完成时再执行f

35-38ms:运行f

45-48ms:运行f

……

了解完js的单线程以后我们开始进入正题,setInterval()

2.setInterval()

语法:setInterval(code,millisec[,"lang"])

code:必须,要调用的函数或执行的代码串

millisec:必须,周期性执行或调用code之间的时间间隔,以毫秒计。

解释:

setInterval的millisec指定的是开始执行code之间的间隔,但并不考虑code本身所消耗的时间,所以实际运行时,setInterval两次执行之间的时间间隔会小于millisec所指定的时间。下面由一个例子来具体解释一下。

setInterval("run()",1000);
function run(){
  {耗时500ms的操作}
}
           

那么这个例子运行时,在等待1000ms之后,开始执行run(),run()执行完毕需要500ms。当run()执行完毕后,再过500ms时,将再次执行run()。因为setInterval指定的是开始执行的间隔,而不考虑执行任务本身所消耗的时间。所以实际运行时,两次执行code的时间会小于定义的millisec。

那么这种情况就很容易发生任务“堵塞”,比如当code定义的任务非常耗时,超过了millisec,那么当code完成一次后就会立刻开始下一次code执行,因为任务进行了累积,在很短的时间内连续触发。比如在代码中我们定义了ajax请求,那么如果任务进行了累积,则很可能会产生集中发出ajax请求的情况。

为了解决这种累积问题,确保两次执行之间有固定的时间间隔,我们可以不采取setInterval,而是采取setTimeout这种方法。

3.setTimeout()

与setInterval一样,setTimeout也允许传入两个参数,一个code,一个millisec

语法:setTimeout(code,millisec)

code:必需。要调用的函数后要执行的 JavaScript 代码串。

millisec:必需。在执行代码前需等待的毫秒数。

但是setTimeout与setInterval不同的是,setTimeout() 只在millisec后执行 code 一次,而非多次执行。

为了实现多次调用code和保证两次执行code之间有固定的时间间隔,同时也解决setInterval的累积问题,我们可以采用在 code 自身再次调用 setTimeout()。

下面通过例子来具体说明:

var number=0;
function numCount(){   
        number=number+1;   
	alert(number);   
	setTimeout(numCount,1000);
}
setTimeout(numCount,1000);
           

上面的例子的运行结果就是每一秒弹出一个对话框并显示number,确保了两次执行的间隔是1000ms。

对于setInterval的使用,html5规定,millisec的最小值为10,也就是两次code的执行间隔最短不能小于10ms,小于10ms 的时间间隔也会被调整到10ms。

在实际应用中,当遇到需要定时器时,建议大家尽量避免setInterval,这样会减少一些不必要的问题。可以利用setTimeout的嵌套来替代setInterval。

如需转载请注明出处。

继续阅读