定时器(setTimeout)的秘密

美美哒武功山

原文地址:→传送门javascript

写在前面

setTimeout()是你们再熟悉不过的定时器,但平时对定时器的了解甚少,因而想看看setTimeout()的原理机制。html

setTimeout()基础

setTimeout()函数用来指定某个函数或某段代码,在多少毫秒以后执行。它返回一个整数,表示定时器的编号,之后能够用来取消这个定时器。java

var timeer = setTimeout(function|code,delay);

注:其中为code时须要以字符串形式传入,通常都是使用传入function的形式。chrome

setTimeout(func,delay,arg1,arg2···)浏览器

setTimeout()可传入多个参数,第三个参数起是做为回调函数的参数传入。函数

function add(a,b){
            console.log(a+b);
        }
        setTimeout(add,4000,20,30);  //20和30做为add的参数传入 结果为50

HTML5规定setTimeout()的最短期间隔是4ms,对于不处在当前窗口的页面,浏览器会将时间间隔扩大到1000ms,若笔记本电脑处于电池供电状态,chrome及IE9以上版本,会将时间间隔切换到系统定时器,约15.6ms。oop

setTimeout()中回调函数的指向

setTimeout()回调函数调用的是某个对象的方法,则其中this指向的是setTimeout所处的环境而并不是指向该对象环境。性能

可以使用ES5中的bind()方法解决this指向,即将对象环境绑定到要执行的回调函数上便可。this

var name = 'lily';
        function Person(name){
            this.name = name;
            this.printName = function(){
                console.log(this.name);
            }
        }

        var person01 = new Person('jike');
        
         //此处的this.name为window下的name,因此是'lily'
        window.setTimeout(person01.printName,1000); 
        
        //此处将printName绑定在person01上,因此this.name的值为'jike'
        window.setTimeout(person01.printName.bind(person01),2000);  
        
        //将printName中的this.name与person01限定在同一个做用域中,因此结果是'jike'
        window.setTimeout(function(){person01.printName();},3000); 
        
        //借助ES6中的箭头函数也能够解决问题
        window.setTimeout(() => {person01.printName},1000);

setTimeout运行机制

setTimeout()和setInterval()的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。若是到了,就执行对应的代码;若是不到,就等到再下一轮Event Loop时从新判断。这意味着,setTimeout()指定的代码,必须等到本次执行的全部代码都执行完,才会执行。code

例如:

task1();
setTimeout(otherTask,1000);
task2();

其中task1和task2为当即执行任务,otherTask被指定在1s后执行,此时otherTask被添加到任务队列的尾部,要等当前的脚本中Event Loop的任务队列所有执行完成后,才开始执行otherTask,但若是task1和task2很耗时,前面的任务超过1s还未结束,此时otherTask只能等task1和task2运行结束,才会执行otherTask。

setTimeout(func,0)的运用

当延迟时间设为0时,即当前任务队列一结束就当即执行func。(换个角度说就是同步任务的任务队列结束后尽早执行。)

task01();
        setTimeout(function(){
            console.log('hello!');  //在task01和task02结束后当即打印hello!
        },0)
        task02();

0ms在其实是达不到的,根据HTML5标准,setTimeout()推迟执行的时间最少是4ms,若是小于这个值,会被自动增长到4,同时也是为了防止多个setTimeout(func,0)语句连续执行,形成性能问题。

  • setTimeout(func,0)能够调整事件的发生顺序。

clearTimeout()

setTimeout()和setInterval()函数,都返回一个表示计数器编号的整数值,将该整数传入clearTimeout()和clearInterval()函数,就能够取消对应的定时器。两种定时器用的同一个编号池。

setTimeout()和setInterval()函数返回的整数值都是连续的,所以能够利用循环来清除全部的定时器。

防抖动(debounce)

该方法用于防止某个函数在短期内被密集调用,具体来具体来讲,debounce方法返回一个新版的该函数,这个新版函数调用后,只有在指定时间内没有新的调用,才会执行,不然就从新计时。

实际中不要设置太多个setTimeout()和setInterval(),它们耗费CPU,理想作法是将要延迟执行的代码都放在同一个函数里,而后支队这个函数使用setTimeout()和setInterval()。

setInterval()

setInterval()使用原理机制与setTimeout()同样,区别就是setInterval()是每隔多少ms执行一次回调函数。也能够传入大于两个参数。

setInterval()指定的是“开始执行”之间的间隔,并不考虑每次任指定的是“开始执行”之间的间隔,并不考虑每次任,好比,setInterval()指定每100ms执行一次,每次执行须要5ms,那么第一次执行后95ms后,第二次执行就会开始。若是某次执行须要105ms,即超过了delay时间,则执行结束后下一次执行就会当即开始。

setInterval()的最短间隔是10ms,小于10ms的时间间隔会被调整到10ms

setInterval()具备累积效应,若是某个操做特别耗时,超过了setInterval()的时间间隔,排在后面的操做就会被累积起来,而后在很短的时间内连续触发,这可能会形成性能问题。

资源参考

相关文章
相关标签/搜索