从js运行机制看setTimeout与setInterval

setTimeout:超时调用;
setInterval:间歇调用

调用时,代码是在全局环境中执行的,里面的this在正常模式下指向window,严格模式下指向undefined

参数:

  • 第一个参数为字符串或者函数(建议使用函数,传递字符串可能导致性能损失)
  • 第二个参数为以毫秒表示的时间,该时间表示多少毫秒后将当前任务加入任务队列。
    注意:对于定时器,是准时添加的,但不是准时执行的。

返回值:
调用setTimeout和setInterval后会返回一个数值ID,可以用来取消定时器

取消:
clearTimeout(timeoutId)clearInterval(intervalid)
注意:取消超时调用的重要性远远高于间歇调用。因为间歇调用会一直执行,直到页面卸载。

两者的相同点

这两者都属于异步任务,由render进程下的定时器触发线程进行计数。
如:

setTimeout(function(){
    console.log("Hello,lwf");
},1000);

当执行到如上代码时,首先上述代码除回调函数部分会进入任务栈,由js引擎线程(js内核)执行,发现是一个定时器(异步任务),由定时器触发线程开始计数。100ms后,将回调函数放入事件触发线程管理的任务队列中,继续等待,当执行栈和任务队列中前面代码都执行完毕后,将第一个参数表示的任务放入执行栈中开始执行,输出“Hello lwf”。(可以看出定时器是准时添加、不准时执行的)

两者的不同

本质上在于添加到任务队列的次数不同,setTimeout向任务队列中添加一次任务,setInterval间隔一定时间后就要向任务队列中添加一次任务。

使用setTimeout,而不使用setInterval,经常使用setTimeout来模拟setInterval
  1. 为什么?

    使用setInterval的一些问题:
    1). 累计效应(上面提到的),如果setInterval代码在(setInterval)再次添加到队列之前还没有完成执行,就会导致定时器代码连续运行好几次,而之间没有间隔。就算正常间隔执行,多个setInterval的代码执行时间可能会比预期小(因为代码执行需要一定时间)

    2). 譬如像iOS的webview,或者Safari等浏览器中都有一个特点,在滚动的时候是不执行JS的,如果使用了setInterval,会发现在滚动结束后会执行多次由于滚动不执行JS积攒回调,如果回调执行时间过长,就会非常容器造成卡顿问题和一些不可知的错误

    扫描二维码关注公众号,回复: 1620591 查看本文章

    3). 把浏览器最小化显示等操作时,setInterval并不是不执行程序,它会把setInterval的回调函数放在队列中,等浏览器窗口再次打开时,一瞬间全部执行时

  2. 使用setTimeout模拟setInterval的例子
    使用回调函数:

var num=0;
var max=10;

function incrementNumber(){
    num++;
    console.log(num);
    if(num<max){
        setTimeout(incrementNumber,500);
    }else{
        console.log("done");
    }
}

incrementNumber();
  1. 使用setTimeout模拟setInterva和setInterval的不同

每次setTimeout计时到后,就会把任务加入任务队列。等待执行栈和任务队列前面的任务执行完后才能执行。之后再次遇到setTimeout,将任务再次加入任务队列。可以看出两次添加到任务队列的时间是不确定的,有误差(等待时间和执行时间)。setInterval每次都是精确地间隔一定时间,将任务加入任务队列。

定时器的应用

计时、指定时间内实现页面跳转、动画等

正向计时的例子,显示为 00:00:00 的形式:

                var h=0;
                var m=0;
                var s=0;
                var mysetInterval=setInterval(timer, 1000);
                function timer(){
                    s++;
                    if(s>=60) {
                        s=0;
                        m++;
                    }
                    if(m>=60) {
                        m=0;
                        h++;
                    }
                    time.innerHTML=checkTime(h)+':'+checkTime(m)+':'+checkTime(s);
                }
                function checkTime(i){ //将0-9的数字前面加上0,例1变为01
                    return  i<10 ? "0"+i:i;
                }

猜你喜欢

转载自blog.csdn.net/liwenfei123/article/details/80671132