井井客

搜索

JS如何控制连续触发事件

关于控制JS中的连续触发事件,我们常说的三类方法:函数节流、函数防抖、标识变量。

JS如何控制连续触发事件

在连续N次触发事件时,除了考验浏览器性能外,还有就是异步事件的不可控而导致数据的不正确性。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <p>点了按钮<span id="total">0</span>次,实际触发事件<span id="event">0</span>次。</p>
    <button id="addButton">点击按钮计数</button>
<script src="http://www.jingjingke.com/res/js/jquery.min.js"></script>
<script>
    var total = $("#total"),
        event = $("#event");
    $("#addButton").on("click",function(){
        total.html(parseInt(total.html())+1);
        asyncEvent();
    })
    // 模拟异步事件(ajax请求))
    function asyncEvent(){
        event.html(parseInt(event.html())+1);
        setTimeout(function(){
            console.log("执行异步事件完成");
        },1000)
    }
</script>
</body>
</html>

就像上面这样,每点击一次按钮都会触发一次事件,但是这个事件不是马上触发的,很可能会在异步执行完成后,堆积在一块执行。如果异步时间有长有短,那边我们取最后一次数据,则不能保证它是最新数据。

函数节流

函数节流其实就是在连续点击事件时,我们只执行最后一次事件。通过设置定时器,清空与重新设置定时器来完成节流。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <p>点了按钮<span id="total">0</span>次,实际触发事件<span id="event">0</span>次。</p>
    <button id="addButton">点击按钮计数</button>
<script src="http://www.jingjingke.com/res/js/jquery.min.js"></script>
<script>
    var total = $("#total"),
        event = $("#event");
    $("#addButton").on("click",function(){
        total.html(parseInt(total.html())+1);
        throttle.run(asyncEvent,200);
    })
    // 模拟异步事件(ajax请求))
    function asyncEvent(){
        event.html(parseInt(event.html())+1);
        setTimeout(function(){
            console.log("执行异步事件完成");
        },1000)
    }
    // 函数节流
    var throttle = {
        timer:null,
        run:function(fn,time){
            // fn传需要执行的函数(回调函数),time为连续间隔时间
            clearTimeout(this.timer);
            this.timer = setTimeout(fn,time);
        }
    };
</script>
</body>
</html>

函数节流的思想就在throttle对象中,如果点击事件间接在200ms内,则会清除上一个定时器,并重新定义一个新的定时器,用于执行事件(相当于执行任务会延迟200ms)。

函数节流比较多的应用场景是在监听滚动条事件上,在快速滚动的途中我们不需要执行事件,当想当它停顿的时候去执行,很好的提升了性能(但是它也有一个弊端,当事件不间断持续执行,就无法执行到这个事件了)。

函数防抖

我自己感觉函数防抖是函数节流的进阶版,不管它是否连续执行,在一个时间断内总会执行一次。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <p>点了按钮<span id="total">0</span>次,实际触发事件<span id="event">0</span>次。</p>
    <button id="addButton">点击按钮计数</button>
<script src="http://www.jingjingke.com/res/js/jquery.min.js"></script>
<script>
    var total = $("#total"),
        event = $("#event");
    $("#addButton").on("click",function(){
        total.html(parseInt(total.html())+1);
        debounce.run(asyncEvent,200,1000);
    })
    // 模拟异步事件(ajax请求))
    function asyncEvent(){
        event.html(parseInt(event.html())+1);
        setTimeout(function(){
            console.log("执行异步事件完成");
        },1000)
    }
    // 函数防抖
    var debounce = {
        timer:null,
        start:0,
        now:0,
        run:function(fn,time,must){
            // fn传需要执行的函数(回调函数),time为连续间隔时间,must为在某个时间段总会执行一次
            clearTimeout(this.timer);
            // 设置开始时间和当前时间,并计算中间的时间是否大于传过来的时间
            this.now = new Date().getTime();
            this.start = this.start || this.now;
            if(this.now - this.start >= must){
                this.start = this.now;
                fn();
                clearTimeout(this.timer);
                return;
            }
            // 设置定时器(上面如果刚执行了一次函数,就不设置,只在下一次进入时设置)
            this.timer = setTimeout(function(){
                this.start = this.now;
                fn();
            },time);
        }
    };
</script>
</body>
</html>

简单点就像这样,可以对比一下节流的代码,其实相差也不是很大。

标识变量

这个应该是我们在点击按钮提交表单时常用的方法,一般执行这种类似事件时,我们只需要执行一次。有时我们也可以通过设置点击按钮禁用状态,来阻止连续点击按钮触发事件。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <p>点了按钮<span id="total">0</span>次,实际触发事件<span id="event">0</span>次。</p>
    <button id="addButton">点击按钮计数</button>
<script src="http://www.jingjingke.com/res/js/jquery.min.js"></script>
<script>
    var total = $("#total"),
        event = $("#event");
    $("#addButton").on("click",function(){
        total.html(parseInt(total.html())+1);
        asyncEvent.run();
    })
    // 模拟异步事件(ajax请求))
    var asyncEvent = {
        flag:true,
        run:function(){
            var that = this;
            if(that.flag === false){
                return;
            }
            that.flag = false;
            event.html(parseInt(event.html())+1);
            setTimeout(function(){
                console.log("执行异步事件完成");
                that.flag = true;
            },1000)
        }
    };
</script>
</body>
</html>

但是这样其实也有一个问题,就是我的标识变量值的改变是在正确执行这段代码后。如果代码出错,则永远就走不到『执行异步事件完成』,所以这种方法也是需要慎用。

上面的函数节流、函数防抖、变量标识的代码只是我自己的理解,如果有不正确的地方,欢迎交流评论~

文章TAG:JS

作者:井井客整理来源:原创
本文标题:JS如何控制连续触发事件
本文链接:/c/03330.html

上一篇:聊一聊数据库
下一篇:http-server命令行启动http服务器

文章分类

相关阅读

随便看看