setTimeout与setInterval的区别 ,浅析

本文详细对比了setTimeout与setInterval的功能差异,阐述了它们在事件循环中的执行机制,以及如何优化定时任务以确保精确的执行间隔。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

setTimeout与setInterval的区别:
1、setTimeout设置后隔指定时间后只会执行一次
2、setInterval设置后会每隔指定时间执行一次
3、setTimeout一般在方法内部使用达到循环调用的效果
4、setInterval一般在方法外部使用就可以达到循环调用效果

基本知识

  • setTimeout(fn,t),超时调用,超过时间t,就执行fn。
  • setInterval(fn,t),间歇调用,调用周期t,执行fn。
    二者调用后,均返回一个数值ID,此ID是计划执行代码的唯一标识符,可以通过它来取消尚未执行的调用
    clearTimeout(id)clearInterval(id)取消间歇调用的重要性要远远高于取消超时调用,因为在不加干涉的情况下,间歇调用将会一直执行到页面卸载。

重点

1、setTimeout(fn,t)中t告诉JS再过多久把当前任务添加到队列中。并不是执行的到setTimeout就添加任务。如果队列是空,那么添加的代码会立即执行;如果队列不空,那么它就要等前面的代码执行完了以后在执行。
2、setInterval(fn,t),在间歇调用时,会出现一些意外。

setInterval(function () {
    func(i++);
}, 100)

每100毫秒调用一次func函数,如果func的执行时间少于100毫秒的话,在遇到下一个100毫秒前就能执行完:

问题1:但是,当func的执行时间多于100毫秒,在触发下一个func函数时(200ms处),上一个func还没有执行完,那么此时第二个func会在队列(event loop)中等待,直到第一个函数执行完,第二个func立即执行。这样就导致func执行间隔不再是100毫秒。

var y=0;
var x = new Date().getTime();
var d=setInterval(a,500);
function a() {
    y++;
   sleep(1000);
    if(y>=4){
        clearInterval(d)
    }
console.log(new Date().getTime()-x);

}
function sleep(sleepTime){
    var start=new Date().getTime();
    while(true){
        if(new Date().getTime()-start>sleepTime){
            break;    
        }
    }
}

控制台输出:

500毫秒后,第一次调用a函数,执行1000毫秒,结束时一共是1500毫秒,第二次a函数立即执行花费了1000毫秒,并没有在间隔500毫秒。

 

问题2:当第一个函数的执行时间特别长,以致于在执行过程中出发了多个func时,就会导致第3个func及以后的函数被忽视。因为任务队列中不会有两个及以上同一个定时器的回调函数

func的执行时长多于400毫秒,那么在200毫秒处,触发第二个func,第一个没执行完成,之后将第2个添加到空队列中,在300毫秒时,触发第3个func但是任务队列中已经有了第二个func,将第3个func抛弃掉;

优化

如何保证每次执行的间隔一样呢,可以使用setTimeout代替setInterval。例如每隔500ms执行一次b

var y=0;
var z = new Date().getTime();
var t=setTimeout(b,500);
function b(){
    y++;
   sleep(2000)
     if(y>=10){
        clearTimeout(t)
    }else{
        setTimeout(arguments.callee,500);
    }
     console.log(new Date().getTime()-z);
}
function sleep(sleepTime){
    var start=new Date().getTime();
    while(true){
        if(new Date().getTime()-start>sleepTime){
            break;    
        }
    }
}

b函数的执行时长2000毫秒,每隔500毫秒执行一次,那也就是两个b的执行结束的间隔是2500毫秒。和控制台输出的一致。

简写

var timer = setTimeout(function() { 
   执行内容....
    timer = setTimeout(arguments.callee, 2000)//再次调用
  }, 2000);

//timer 就是定时器返回得id,清除定时器时可以直接将这个id传入;

比如说setTimeOut还有以下的用法:

比如说:在处理DOM点击事件的时候通常会产生冒泡,正常情况下首先触发的是子元素的handler,再触发父元素的handler,如果我想让父元素的handler先于子元素的handler执行应该怎么办?那就用setTimeout延迟子元素handler若干个毫秒执行吧。

注:

setTimeout,setInterval都存在一个最小延迟的问题,虽然你给的delay值为0,但是浏览器执行的是自己的最小值。HTML5标准是4ms,但并不意味着所有浏览器都会遵循这个标准,包括手机浏览器在内,这个最小值既有可能小于4ms也有可能大于4ms。在标准中,如果在setTimeout中嵌套一个setTimeout, 那么嵌套的setTimeout的最小延迟为10ms

 

setTimeout和线程的一些关系

var tbody = document.getElementsByTagName("tbody")[0];
for (var i = 0; i < 20000; i++) {
    var tr = document.createElement("tr");
    for (var t = 0; t < 6; t++) {
        var td = document.createElement("td");
        td.appendChild(document.createTextNode(i + "," + t));
        tr.appendChild(td);
    }
    tbody.appendChild(tr);
}

var t2 = +new Date();
console.log(t2 - t1); 

会发现先打印出时间,再渲染页面。
因为Javascript是单线程的(这里不谈web worker),也就是说浏览器无论什么时候都只有一个JS线程在运行JS程序。或许是因为单线程的缘故,也同时因为大部分触发的事件是异步的,JS采用一种队列(event loop)的机制来处理各个事件,比如用户的点击,ajax异步请求,所有的事件都被放入一个队列中,然后先进先出,逐个执行。
另一方面,浏览器还有一个GUI渲染线程,当需要重绘页面时渲染页面。但问题是GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待JavaScript引擎空闲时才有机会渲染出来。

参考文章:http://qingbob.com/difference-between-settimeout-setinterval/

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值