美文网首页
Javascript定时器

Javascript定时器

作者: aabbcczero | 来源:发表于2020-04-10 18:55 被阅读0次

    什么是定时器?

    javascript延时执行的代码即为定时器。定时器通常有两个函数组成:

    setTimeout

    setInterval

    定时器的作用场景?

    轮播图,广告弹窗,动画, 异步等

    定时器的用法和区别?

    setTimeout()

    setTimeout函数用来指定某个函数或某段代码,在多少毫秒后执行(只执行一次)

    语法:

    var timeoutld = setTimeout(func|code,delay)

    timeoutld:定时器id 可以用于销毁这个定时器

    func:用来延期执行的函数 可以在括号外定义或在定时器里面写

    code:用来延期执行的代码

    delay:延期执行多少毫秒

    实例:

    console.log(1) 

    setTimeout(console.log(2),1000)

    console.log(3)

    // 1

    // 3

    // 2

    console.log(1)

    var f = function(){

            console.log(2)

    }

    console.log(3)

    setTimeout(f,1000)

    // 1

    // 3

    // 2

    有一个需要注意的地方 如果调用的函数是对象的内部方法 那么this指向全局而不是对象的内部数据

    var x = 1;

    var obj = function()){

    x:2,

    y:function(){

    console.log(this.x)

    }

    }

    setTimeout(obj.y,1000)

    // 1

    由于匿名函数在全局作用域中执行,所以他指向的是全局变量中的x

    解决办法:

    1.在函数内部执行obj.y

    var x = 1;

    var obj = {

       x:2,

       y:function(){

           console.log(this.x)

       }

    }

    setTimeout(function(){obj.y()},1000)

    // 2 

    2.使用bind方法 把obj.y绑定到obj上面

    var x = 1;

    var obj = {

       x:2,

       y:function(){

           console.log(this.x)

       }

    }

    setTimeout(obj.y.bind(obj),1000)

    // 2 

    setInterval ()

    setInterval 函数用来指定某个函数或某段代码,在多少毫秒后执行(无限次执行)

    var x = 2;

    setTimeout(function(){x++},1000)

    console..log(x) // 3

    console..log(x) // 4

    clearTimeout(),clearInterval()

    clearTimeout,clearInterval都用来清除定时器

    var f = function(){console.log(1)}

    var clear1 = setTimeout(f,1000)

    var clear2 = setInterval(f,1000)

    clearTimeout(clear1)

    clearInterval(clear2)

    防抖和节流

    函数防抖debounce是指函数在某段时间内,无论触发了多少次回调,都只执行最后一次

    为什么要用防抖函数呢,举个例子

    有一个场景 用户在搜索框输入拼音的时候 搜索框会出现智能匹配 但是呢 用户清除一个字母在输入一个字母 会造成不必要的性能浪费(函数多次执行)

    html

    <!DOCTYPE html>

    <html lang="en">

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <title>Document</title>

        <!-- 引入样式 -->

        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">

    </head>

    <body>

        <input type="text" id="input" placeholder="请输入内容"/>

    </body> 

    </html>

    js

    var input = document.getElementById("input")

    var output = function(){

         console.log(1)

    }

    input.addEventListener('keydown',output)

    没有使用防抖函数的场景

    从上面可以看出 函数前前后后执行了8次 然而却没输入数据进去

    第一版

     var input = document.getElementById("input")

     var output = function(){

         console.log(1)

     }

     var debounce = function(func,wait){

         let timeout; //定义一个定时器

         return function(){

             clearTimeout(timeout) //清除之前的定时器

             timeout = setTimeout(func,wait) //设置定时器,延迟执行函数

         }

     }

     input.addEventListener('keydown',debounce(output,1000))

    上面的思路是监听键盘的按键,每当按下键盘时,隔1秒在执行函数。当用户不断输入时,都会取消掉之前设置的定时器而重新设置,这样就保证了只有最后一次操作才能触发

    现在遇到了一个问题 如何通过this来获取当前对象的值呢?

    先输出一下this的值

     var debounce = function(func,wait){

         let timeout;

         return function(){

             clearTimeout(timeout)

             timeout = setTimeout(func,wait)

             console.log(this)

         }

     }

    var output = function(){

         console.log(this)

     }

    当前this的指向

    可以看到 一个this指向了全局对象 一个this指向了当前的元素 如何更改呢?

    可以使用call方法来绑定this指针

    var output = function(){

         console.log(this.value)

     }

     var debounce = function(func,wait){

         let timeout;

         return function(){

             var _this = this;

             clearTimeout(timeout)

             timeout = setTimeout(function(){

                 func.call(_this)

             },wait) 

         }

     }

    当前this的值

    这里通过了Function.prototype.call()的方法改变了this的指向问题,可以获取到当前输入的值了。现在我们再来优化一下

    <script src="pinyin_dict_notone.js" type="text/javascript"></script>//文字转换拼音

    <script src="pinyinUtil.js"  type="text/javascript"></script> //文字转换拼音 

    var input = document.getElementById("input")

     var result = ['张三','李四','王五']

     var resultpinyin = [];

     var pinyin = function(){

        for(var i=0;i<result.length;i++){

            var split = pinyinUtil.getPinyin(result[i]).replace(" ","")

            resultpinyin.push(split)

        }

     }

     var output = function(){

        var parent = document.getElementsByClassName('result')[0].children[0]

        parent.innerHTML = ""

        var value = pinyinUtil.getPinyin(this.value).replace(" ","")

        for(var i=0;i<resultpinyin.length;i++){

            if(value[0] == resultpinyin[i][0] && resultpinyin[i].indexOf(value) != -1){

                var li = document.createElement('li')

                li.innerHTML = result[i]

                var parent =  document.getElementsByClassName('result')[0].children[0]

                parent.append(li)

                var _this = this

                li.addEventListener('click',function(){

                    input.value = this.innerText

                    parent.innerHTML = ""

                })

            }

        }

     }

     var debounce = function(func,wait){

         let timeout;

         return function(){

             var _this = this;

             clearTimeout(timeout)

             timeout = setTimeout(function(){

                 func.call(_this)

             },wait) 

         }

     }

    pinyin()    

    input.addEventListener('keydown',debounce(output,1000))

    现在让我们来看一下节流函数 什么是节流呢?

    如果某个事件持续触发,隔一段时间内,事件才会执行一次

    让我们看个场景 现在许多网站有个返回顶部的功能 以简书为例

    返回顶部

    现在 我们来考虑一下这个功能该如何实现呢?

    首先呢  先输出一下当前浏览的位置

    var scrollTop = document.body.scrollTop ||document.documentElement.scrollTop;

    当浏览器滑动的时候 添加一个函数

    function show(){

        var scrollTop = document.body.scrollTop ||document.documentElement.scrollTop;  

        console.log(scrollTop)

    }

    window.onscroll = show

    有个问题是 浏览器滚动时 函数执行频率太高了 这样很浪费性能 这时候 我们可以用节流函数来做优化

    节流函数有两种方式实现:时间戳和定时器

    第一版

    时间戳

    html

    <body>

        <div style="height: 2000px;"></div>

        <div class="top">

            回到顶部

        </div>

    </body>

    function show(scroll){

            if(scroll > 500){

                document.getElementsByClassName('top')[0].style.display = "block"

            }else{

                document.getElementsByClassName('top')[0].style.display = "none"

            }

            console.log(scroll)

        }

        function throttle(func,wait){

            var previous = 0;

            return function(){

                var nowtime = +new Date()

                if(nowtime - previous > wait){ //判断一下触发事件的时候是否大于设定的时间周期

                    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;

                    show(scrollTop)

                    previous = nowtime

                }

            }

        }

        window.addEventListener('scroll',throttle(show,500))

    这里使用了时间戳的方法,第一次滚动时函数会立马执行,当滚动停止后没有办法在执行事件

    未滚动前 滚动后

    可以看到 只执行了一次事件 现在看看定时器

    function throttle(func,wait){

            var time;

            var previous = 0;

            return function(){

                if(!time){ //判断定时器是否存在

                    time = setTimeout(function(){ //设置定时器

                        time = null //清空定时器 直到下一次执行

                        var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;

                        func(scrollTop)

                    },wait)

                }

            }

    滚动后

    可以看到 当滚动了一段距离后 函数才会执行一次 。

    有没有一种办法 既能让函数在第一次滚动的时候马上执行 在滚动完后也开始执行呢?

    function throttle(func,wait){

            var time,scrollTop;

            var previous = 0;

            var start = function(scrollTop){

                previous = +new Date()

                time = null;

                func(scrollTop)

            }

            return function(){

                var now = +new Date()

                //下次触发func的时间

                var remaining = wait - (now - previous)

                scrollTop = document.body.scrollTop || document.documentElement.scrollTop;

                //如果没有剩余的时间了

                if(remaining <= 0 || remaining > wait){

                    if(time){

                        clearTimeout(time)

                        time = null;

                    }

                    previous = now;

                    func(scrollTop)

                }else if(!time){

                    time = setTimeout(start,remaining)

                }

            }  

        }

    这里判断一下上次执行的时间和这次触发的时间是否大于执行周期,如果大于则判断定时器是否存在,存在则清除之前设置的定时器,重新设置。

    回到顶部功能

    var backTop = document.getElementsByClassName('top')[0]

        backTop.addEventListener('click',function(){

            window.scrollTo(0,0);  

        })

    参考链接

    https://wangdoc.com/javascript/async/timer.html

    https://www.javascriptc.com/2283.html

    https://www.javascriptc.com/2285.html

    相关文章

      网友评论

          本文标题:Javascript定时器

          本文链接:https://www.haomeiwen.com/subject/isjdmhtx.html