使用setTimeout()方法来模拟setInterval()与直接使用setInterval()有什么区别?

setTimeout(fn, time),超时调用,在时间大于等于 time  时调用;

setInterval(fn, time),是间歇调用,每隔 time 调用一次。从载入后,每隔指定的时间就执行一次表达式,只要窗口不关闭或 clearInterval() 调用就会无限循环下去

         虽然两者不一样,但是却可以相互模拟。具体使用那个,以具体的需求和场景具体分析,就像for循环可以模拟所有的循环一样(包括分支,以及do while一样)。一般情况下 setTimeout() 用于延迟执行某方法或功能;setInterval() 则一般用于刷新表单,对于一些表单的假实时指定时间刷新同步

这种重复定时器的规则有两个问题:

1. 某些间隔会被跳过 

2. 多个定时器的代码执行时间可能会比预期小。

为了避免setInterval()的重复定时器的这两个缺点,可以使用模拟setInterval

var intervalNum = 0;
function testsetInterval() {
    var date = new Date();
    console.log(date.getSeconds());
    console.log("setInterval", intervalNum++);
}
function recursive() {
    testsetInterval();
    setTimeout(function () {
        recursive()      //递归,每隔4秒调用一次recursive()
    }, 4000)
}
function testFuntion() {
    recursive();        //在方法recursive外,调用一次recursive,以启动循环调用!
}

  模拟 setTimeout() :用 setInterval() 模拟 setTimeout() 很简单,在 setInterval() 执行一次后,立刻关闭窗口(当然这是耍无赖)或者执行 clearInterval() 方法(这个靠谱点)。clearInterval() 需要在 setInterval()执行code方法内或其他地方执行,不能紧接着 setInterval() 后面执行,那样setInterval() 还没等到执行,就已经被干掉了

var intervalNum = 0, clearId = 0;
function testsetInterval(){
    var date = new Date();
    console.log(date.getSeconds());
    console.log("setInterval", intervalNum++);
    clearInterval(clearId);     //也可以在此执行
}
function testFuntion() {
    clearId = setInterval(function () {
        testsetInterval();          //每隔4秒调用testsetInterval()
        // clearInterval(clearId);     //可以在此执行
    },4000);
}


上面实现了递归调用,这样做的好处是:在前一个定时器代码执行完成之前,不会向队列插入新的定时代码,确保不会有任何的缺失间隔。而且,它保证在下一次定时器代码执行之前,至少要等待指定的时间间隔。

 

避免双重求值”,解释为什么 “ 建议传入函数而不是字符串以作为第一个参数”。  

   setTimeout()、setInterval() 允许传入一个JS代码字符串并执行,然而在JS代码中执行另一段JS代码时,代码首先会以正常的方式求值,然后在执行过程中对包含于字符串中的代码发起另一个求值运算,从而造成双重求值。它比直接包含的代码执行速度慢很多,原因在于, 每次调用setTimeout()、setInterval()都会创建一个新的解释器/编译器实例。这必然使得代码执行速度变慢,效率降低,从而造成性能的浪费。所以建议传入函数而不是字符串来作为第一个参数。

 再次借用大佬的代码,一个小测试。从 0 自加到 1亿,比较两种方式各自的实际耗时,代码以及测试结果如下:

var Timer ={     //从书上copy的一个JS代码时间分析对象
    _data : {},
    start:function (key) {
        Timer._data[key] = new Date();
    },
    stop:function (key) {
        var time = Timer._data[key];
        if(time){
            Timer._data[key] = new Date()-time;
        }
    },
    getTime:function (key) {
        // return Timer._data[key];
        console.log("time = "+ Timer._data[key]);
    }
};

var intervalNum = 100000000, clearId = 100000000;
function testsetInterval(){   //计算从0 加到 1亿,以 传入函数方式 执行
    var temp = 0;
    while(intervalNum--){
        if(temp !== 0){
            temp = temp + intervalNum;
        }else {
            temp = (intervalNum+1) + intervalNum;
        }
    }
    console.log(temp);
    Timer.stop("testsetInterval");      //调用stop(),计算时间差
    Timer.getTime("testsetInterval");   //将时间差值打印出来
}
function testsetTimeout(){      //计算从0 加到 1亿,以 字符串方式 执行
    var temp = 0;
    while(clearId--){
        if(temp !== 0){
            temp = temp + clearId;
        }else {
            temp = (clearId+1) + clearId;
        }
    }
    console.log(temp);
    Timer.stop("setTimeout");       //调用stop(),计算时间差
    Timer.getTime("setTimeout");    //将时间差值打印出来
}
function testFuntion() {
    Timer.start("testsetInterval");     //获取代码执行前的初始时间
    setTimeout(function () {
        testsetInterval();      //每隔1秒调用testsetInterval()
    },1000);

    Timer.start("setTimeout");
    setTimeout("testsetTimeout()",1000);    //双重求值模式,每隔1秒调用testsetTimeout()
}

  

 看得出,“双重求值”对性能影响还是蛮大的。虽然现在的CPU主频都相当高,处理数据相当快,而平时前端处理数据的数量级,也不见得能达到这么高,但是养成一种好的编程习惯和塑造提高代码性能的思想总没得错!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值