1.背景介绍
   什么是定时器?
JS提供了一些原生方法来实现延时去执行某一段代码。

我们在JS中一般会使用以下两种定时器

setTimeOut( )  setInterval( )

   setTimeout
        暂停指定的毫秒数后执行指定的代码

   setInternval
        间隔指定的毫秒数不停地执行指定的代码。

2.知识剖析
 

    setTimeOut:
         语法:setTimeOut(code,millisec)
         这个方法所有浏览器都支持,setTimeout( ) 是属于 window 的 method, 但我们都是略去 window 这顶层物件名称, 这是用来设定一个时间, 时间到了, 就会执行一个指定的 method。
         code:必需,要调用的函数或执行的JavaScript代码;
         millisec:必需,在执行代码前需等待的毫秒数。
         该定时器只执行一次,若需要多次调用,可使用setInterVal()或让code自身再次调用setTimeOut()。
         返回值: 一个可以传递给 Window.clearTimeOut() 从而取消对 code 的周期性执行的值。
         清除定时器:
              语法:clearTimeOut(str)
              为了更方便的清除指定定时器,就必须在用定时器的时候,定义一个变量来记录定时器的返回值。比如:
                var str = setTimeOut(test,1000);

    setInterVal:
        语法:setInterval(code,millisec)
         setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。setInterval() 方法会不停地调用函数,直到clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。
         code:必需。要调用的函数或要执行的代码串。
         millisec:必须。周期性执行或调用 code 之间的时间间隔,以毫秒计。
         返回值: 一个可以传递给 Window.clearInterval() 从而取消对 code 的周期性执行的值。
         清除定时器:方法与 setTimeOut() 相同。
             语法:clearInterval()

        这两种定时器,设置方法有区别,但是清除方法是等效的,就是无论你设置的定时器是哪一种 都可以使用上边任意一种清除代码清除掉。

3.常见问题
    setInterval多次调用后执行频率为什么越来越快?
      当我们在启动一个定时器时,电脑会为我们开启一个定时器,当我们再次用同一个名字开启定时器时,电脑会再开另外开启一个定时器,与先前开启的定时器无关,我们所谓的定时器的名字,它只是一个变量而已,并不是定时器的名字,它的功能是清定时器用的,也就是通过clearInterval(变量)使定时器停止运行。
      <!----  setInterval() 的运行模式是按照指定的周期(以毫秒计)来调用函数或计算表达式。
            这就使得在某个多次执行或者重复执行事件中创建的setInterval()都会独立的保留下来。 ---->

4.解决方案

    方案一:每次调用前清除定时器

  var timer;  

  var flashStart = function () {
        clearTimeout(timer);
        timer = setInterval(function(){
                / 代码块…… /
            },1000);
    };

    方案二:给定时器加一个开关

        var switch = 'off';
        var timer;
        var function test(){
            if(switch === 'off'){
                timer = setInterval(function(){
                    / 代码块…… /
                },1000);    
            }
            switch = 'on';
        }

5.编码实战
    
6.扩展思考
    若参数 millisecs 为 0 ,会发生什么?
    Javascript是单线程执行的,也就是无法同时执行多段代码,当某一段代码正在执行的时候,所有后续的任务都必须等待,形成一个队列,一旦当前任务执行完毕,再从队列中取下一个任务。这也常被称为“阻塞式执行”。
    如果代码中设定了一个setTimeout,那么浏览器便会在合适的时间,将代码插入到任务队列中,如果这个时间设为0,就代表立即插入到队列,但不是立即执行,仍要等待前面代码执行完毕。所以setTimeout并不能保证执行的时间,是否及时执行取决于javascript 线程拥挤还是空间。

function order(){
        console.log(1);
        num = 2;
        var timer = setTimeout("console.log(num)",0);
        console.log(3);
    };

// 输出为 1,3,2

    

7.参考文献
    参考一:
        JavaScript定时器实现的原理分析
    参考二:
        BOM系列第一篇之定时器setTimeout和setInterval
    参考三:
        setTimeout和setInterval从入门到精通

8.更多讨论
    如何动态改变定时器的时间间隔?

    使用定时器可以实现哪些有趣的功能?

9.提问互动
    1.setInterval、setTimeout 中的函数引用,带引号和不带引号有什么区别?

       答:带引号的“test()”和不带引号的 test 是一样的,都是表示 test 函数,在一定时间时候调用该函数。而将带引号的方法去掉引号,变成 test(),则在解析到定时器这一行的时候,会发现 test()是函数调用(执行),会先进行函数调用,便将定时器忽略掉了。所以要是带括号的话,必须要加引号。

    2.setTimeOut 只能用于单次执行吗?

        答:不是的。若想要多次调用,可以让 code 自身再次调用 setTimeOut。demo如下:

function test(){
        console.log("咕咕咕")
        ggg = setTimeout(test,1000);
    };

    3.关于 setTimeOut 的this指向哪里?

        答:setTimeout方法是挂在window对象下的。超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined。


用户bPbdDlb
422 声望36 粉丝