菜鸟理解setTimeout和setInterval

写在前面,最近在准备校招,陆陆续续作一些以前的总结,写了一个小系列的文章,想借此机会记录下来,也能之后有个地方能进行查阅,上一篇文章在css基础总结但愿能帮助一下和我同样的菜鸟们好了,正文开始。javascript

这是一个老生常谈,新手掉坑的问题,算是一个比较经典的对于javascript运行机制的理解问题,我在这里粗浅的谈一下本身的理解,话很少说,进入正题:css

二者表面上的区别

  1. setTimeout() 方法用于在指定毫秒数以后调用其中的函数html

  2. setInterval() 方法则是在间隔必定毫秒后重复调用其中的函数java

透过现象看本质

时间精确问题

因为js是运行在单线程的环境当中的,单线程就意味着任务的执行须要依赖任务队列。实际运行时是将两个方法的代码块移出当前运行环境(从任务队列移出到回调队列中),当执行完当前任务后,检查回调队列中有无须要执行的任务(对应这两个方法为是否已经到执行时间),但是若是时间到时刚好有别的任务在进行的话,因为其单线程的机制,该方法就只能等到当前任务结束以后才能运行。segmentfault

回到方法自己,这就至关于其余的正常任务在一个队列中,当遇到这两个方法时,就将他们移出队列,并开始计时,当时间到时,直接“插队”到队首,若是队首有正在执行的任务,则排在次队首,等待执行。也就是说,这仅仅是“计划”在将来某一个时间执行某个任务,并不能保证精确的时间。闭包

setInterval重复执行问题

这个方法执行时仅当没有该计时器的其余代码示例时才进行下一轮的执行。这样的规则就会致使某些间隔会被跳过,同时多个间隔可能比预期时间要短。因此为了不setInterval所形成的问题,能够用setTimeout来经过循环代替setInterval方法,从而实现一个重复的定时器(除非必要,尽可能避免代码中出现setInterval)函数

方法中使用this的问题

在两个方法中传入函数时(即第一个函数参数中含有另一个函数),此函数中的this会只想window对象。这是因为两个方法调用的代码在与所在函数彻底分离的执行环境上(第一条中有讲到的两个方法的运行机制),这就会致使这些代码中包含的this关键字会指向window(或全局)对象。this

可是要注意,若是this只是在两个方法中而不是在方法中的函数中时,this的指向符合咱们的预期为当前对象。prototype

解决方法:

1.将当前对象的this存为一个变量,定时器内的函数利用闭包来访问这个变量,以下:线程

var num = 0;
function Obj (){
    var that = this;    //将this存为一个变量,此时的this指向obj
    this.num = 1,
    this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
            console.log(that.num);    //利用闭包访问that,that是一个指向obj的指针
        }, 1000)
    }
}
var obj = new Obj;
obj.getNum();          //1  打印的为obj.num,值为1
obj.getNumLater()      //1  打印的为obj.num,值为1

2.利用bind()方法:

var num = 0;
function Obj (){
    this.num = 1,
    this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
            console.log(this.num);
        }.bind(this), 1000)    //利用bind()将this绑定到这个函数上
    }
}
var obj = new Obj;
obj.getNum();                 //1  打印的为obj.num,值为1
obj.getNumLater()             //1  打印的为obj.num,值为1

bind()方法是在Function.prototype上的一个方法,当被绑定函数执行时,bind方法会建立一个新函数,并将第一个参数做为新函数运行时的this。在这个例子中,在调用setTimeout中的函数时,bind方法建立了一个新的函数,并将this传进新的函数,执行的结果也就是正确的了。关于bind方法可参考 MDN bind

清除计时器

clearTimeout()

在在使用setTimeout时,该方法会返回一个惟一的关于当前计时器的计时ID,在clearTimeout()方法中传入这个ID值便可取消对应的Timeout

clearInterval()

同上

参考

上面是我在使用过程当中遇到问题后在网上查阅后本身的一些总结,但愿对和我同样的新手有所帮助,想要更深刻了解他们的区别和js的一些运行机制,请入传送门:

传送门1---阮大的剖析

传送门2---this指向

传送门3---调用执行

相关文章
相关标签/搜索