防抖与节流

223 阅读2分钟

一段代码写完了,并不是结束了,作为一个有工作经验的程序员首先会自己做一个简单的单元测试,确保实现的语法和功能是没有问题的,同时也可以考虑一下自己代码是不是存在着优化的可能。那么今天我们来聊一下前端优化的两个小技巧,防抖和节流。

防抖

防抖 (Debouncing) 的含义是指在一定时间内,多次触发同一个事件,只执行最后一次操作,就好像,到饭馆吃饭点餐,指着菜单上的菜,对服务员说:要,要,要,要不起。尽管说了很多要,实际上意愿是最后的要不起。(生活当中建议不要尝试,我有个朋友吧.....)

案例

最常见的操作就是,在监听input框的输入的时候,如果不做特殊的设置,用户每输入一个字符,就会请求服务器1次,其实,这个时候请求服务器携带的输入内容还不是最新的,那么这样就会给服务器带来很大的压力。

<script>
    function requester(url) {
        let xmlhttp = "";
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
​
        xmlhttp.open('get',url,async);
        xmlhttp.send();
        xmlhttp.onreadystatechange=function(){
            if(xhr.readyState ===4){
                if(xhr.status === 200){
                    var text=xhr.responseText;
                }else{
                    text='获取失败';
                }
                console.log(text);
            }
        }
    }
    var hello_input = document.getElementById("hello");
    hello_input.oninput = function (obj) {
        let value = hello_input.value;
        console.log(value);
        requester("http://www.dazejz.club?query="+value)
    };
</script>

上面的代码,input每次输入一个字符,下面所有的ajax就会请求一次,服务端的小伙伴都感动哭了。

优化思路

既然明白了上面出现的问题,那么优化的思路自然也就有了,就是降低input请求的次数,那么我们可以有两种方案。

1、修改事件,在input完全输入完进行提交,这里可以采用blur事件,或者添加按钮来触发请求。

<script>
//......
    var hello_input = document.getElementById("hello");
    hello_input.blur = function (obj) {
        let value = hello_input.value;
        console.log(value);
        requester("http://www.dazejz.club?query="+value)
    };
</script>

2、设置一个计时器,input触发之后,调用这个计时器延时执行请求,如果在没有到计时器发起请求的时间再次发起请求,那么重置这个计时器(之前的哪一个计时器被清除,所以没有触发执行):

<script>
//......
hello_input.oninput = function () {
    let value = hello_input.value;
    clearTimeout(timer); //如果在距离上次调用不足1000毫秒的时候,再次调用函数,那么上次的定时器在没有执行前被取消
    timer = setTimeout(()=> {
        requester("http://www.dazejz.club?query="+value)
    }, 1000) //从新设置一个延时的计时器来指向请求
};
//这段代码只是用来聊防抖,还需要进行优化,小伙伴们可以琢磨琢磨,嘿嘿嘿
</script> 

但是这里要结合需求去优化,比如input框当中要实现类似百度的输入补全功能,就不可以进行优化,优化功能要和实际需求结合起来。

节流

防抖固然解决了无用请求给服务器带来压力的问题,但是上面的案例一直输入,那么定时器被一直清除,是不是就永远不会发起请求,这种情况下还是有问题的,那么就需要考虑节流的问题了。

节流 (Throttling) 的含义是指在一定时间内,多次触发同一个事件,只执行第一次操作。

优化思路

那么很显然,防抖的解决方案是如果你不满一秒再次请求,那么就从小定义计时器,节流就更简单了,设置一个阈值,比如:

<script>
    function requester(url) {
        let xmlhttp = "";
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
​
        xmlhttp.open('get',url,async);
        xmlhttp.send();
        xmlhttp.onreadystatechange=function(){
            if(xhr.readyState ===4){
                if(xhr.status === 200){
                    var text=xhr.responseText;
                }else{
                    text='获取失败';
                }
                console.log(text);
            }
        }
    }
    window.onload = function () {
        let obj = document.getElementById('hello');
        let callback = throttlingFun();
        obj.addEventListener('keyup',()=>{
            let val = obj.value;
            callback(val)
        },false)
    };
​
    function throttlingFun() {
        var flag = false;
        return function(value){
            if(hasdone)
            {
                return; // 如果 flag = true 则直接返回,不执行
            }
            // 设置已经执行
            let url = "http://www.dazejz.club?query="+value;
            requester(url);
            flag =true;
            time = setTimeout(() => {
                flag = false //2000后设置flag 为能够再次执行
            }, 2000);
        }
    }
</script>

关于防抖和节流就先聊这么多,欢迎各位大佬多多指点。