资讯专栏INFORMATION COLUMN

菜鸟理解setTimeout和setInterval

sixleaves / 3013人阅读

摘要:也就是说,这仅仅是计划在未来某一个时间执行某个任务,并不能保证精确的时间。重复执行问题这个方法执行时仅当没有该计时器的其他代码示例时才进行下一轮的执行。这样的规则就会导致某些间隔会被跳过,同时多个间隔可能比预期时间要短。

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

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

两者表面上的区别

setTimeout() 方法用于在指定毫秒数之后调用其中的函数

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

透过现象看本质 时间精确问题

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

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

setInterval重复执行问题

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

方法中使用this的问题

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

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

解决方法:

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---调用执行


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84222.html

相关文章

  • 前端校招准备系列--js中的setTimeout到底是什么?

    摘要:浏览器是多进程的,而浏览器的内核渲染进程是多线程的。如果已经将回调函数放进任务队列,但是主线程正在执行一个非常耗时的任务,当这个任务执行完毕后,主线程去任务队列中取任务,这个时候,就会出现连续执行的情况,也就是说相当于失效了。 前言   在刷笔试题的时候,经常会碰到setTimeout的问题,只知道这个是设置定时器;但是考察的重点一般是在一个方法中包含了定时器,定时器中的打印和方法中打...

    Godtoy 评论0 收藏0
  • Javascript学习总结 - JS基础系列三

    摘要:案例每隔毫秒调用函数并显示时间。当点击按钮时,停止时间代码如下计时器每隔毫秒调用函数,并将返回值赋值给计时器计时器,在载入后延迟指定时间后去执行一次表达式仅执行一次。该值标识要取消的延迟执行代码块。 简述 本系列将持续更新Javascript基础部分的知识,谁都想掌握高端大气的技术,但是我觉得没有一个扎实的基础,我认为一切高阶技术对我来讲都是过眼云烟,要成为一名及格的前端工程师,必须把...

    zlyBear 评论0 收藏0
  • JS事件循环,了解一下

    摘要:任务队列中的代码被加载到函数调用栈中去执行。说到这里,你基本上对事件循环有个大致的了解了。 在理解事件循环之前,我总会遇到一些奇奇怪怪的问题:比如明明已经调接口拿到了数据,可是跟在调数据之后的操作却没有正常执行;又或者不知道为啥,代码里非得加个setTimeout才能正常跑通;特别是在运用Promise的时候,更是有各种问题百思不得解。遇上问题要解决,更要知道问题产生的原因,这样才能h...

    xbynet 评论0 收藏0
  • setTimeoutsetInterval

    摘要:一个页面在浏览器显示出来至少需要个线程,分别是引擎,渲染,事件触发。其中事件触发是独立于其他个执行的,而和是相互排斥的,也就是说同一个时间二者只有一个在工作。 作为DOM本身十分重要的2个异步执行函数,初学者感觉这个很不好理解,我简单写一写我的理解 setTimeout (func, millisec); setInterval(func, millisec); 这两个方法在形式看起来...

    SnaiLiu 评论0 收藏0
  • 理解javascript中的事件循环(Event Loop)

    摘要:主线程会暂时存储等异步操作,直接向下执行,当某个异步事件触发时,再通知主线程执行相应的回调函数,通过这种机制,避免了单线程中异步操作耗时对后续任务的影响。 背景 在研究js的异步的实现方式的时候,发现了JavaScript 中的 macrotask 和 microtask 的概念。在查阅了一番资料之后,对其中的执行机制有所了解,下面整理出来,希望可以帮助更多人。 先了解一下js的任务执...

    mykurisu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<