虾扯蛋之函数防抖和节流

5,115 阅读4分钟

背景

    今天在coding的时候,做了一个搜索框,也正是这个搜索框,让我和后台小伙伴直接由铁磁变为塑料兄弟。那到底发生啥了呢?其实很简单,其实很无奈,就是我用王者的手速把他的接口访问崩了!

    我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求,onmousemove,resize,onscroll等等,有些时候,我们并不能或者不想频繁触发事件,咋办呢?这时候就应该用到函数防抖和函数节流了!

函数防抖(debounce)

    什么是防抖?短时间内多次触发同一个事件,只执行最后一次,或者只在开始时执行,中间不执行。举个栗子:你去乘坐公交车,不停地上人,连续上人的过程中司机师傅是不会开车的,只有当最后一个人上车了,老司机才会开车!嘿嘿嘿!我们以不停地触发onmousemove事件,让数字+1为例。代码如下:

  • 不使用防抖和节流,数字会像得了羊癫疯一样不停地增长
//变量初始化
var xcd = document.getElementById('xcd'),
    count = 1; 
//要执行的操作 数字+1
function doSomething() {
    xcd.innerHTML = count++;
};
//触发onmousemove事件 正常情况下
xcd.onmousemove = doSomething;

  • 使用防抖之绿色基础版
//绿色基础版:
function debounce(doSomething,wait){
    var timeout;//需要一个外部变量,为增强封装,所以使用闭包
    return function(){
        var _this = this,
            _arguments = arguments;//arguments中存着e
        clearTimeout(timeout);
        timeout = setTimeout(function(){
            doSomething.apply(_this,_arguments);   
        },wait);
    }
}
//触发onmousemove事件
xcd.onmousemove = debounce(doSomething,1000);

    这个绿色基础版虽然简单,但是已经能够解决大部分需求场景了,没有啥特殊需求使用这个版本就行了!用起来简直像吃了巴豆一样,duangduangduang,极其通畅!But,还会有一些其他需求,比如我想立即执行,就是连续触发事件的开始时立即执行一次,后连续触发不执行,我们用isImmediate表示是否立即执行,代码如下:

  • 使用防抖之立即执行版
//立即执行版
function debounce(doSomething,wait,isImmediate){
    var timeout;
    return function(){
        var _this = this,
            _arguments = arguments;
        clearTimeout(timeout);
        if(isImmediate){
            var isTrigger = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            isTrigger&&doSomething.apply(_this,_arguments);
        }else{
            timeout = setTimeout(function(){
                doSomething.apply(_this,_arguments);   
            },wait);
        }
    }
}
//触发onmousemove事件
xcd.onmousemove = debounce(doSomething,1000,true);

函数节流(throttle)

    什么是节流?节流是连续触发事件的过程中以一定时间间隔执行函数。节流会稀释你的执行频率,比如每间隔1秒钟,只会执行一次函数,无论这1秒钟内触发了多少次事件。

    举个栗子:你每天要喝好多水,但是你不会每喝完一口水都要去一次厕所,如果有盆友是酱紫的话,我劝你还是去医院看看吧→_→厕所看你都烦~你虽然一直在喝水,但是不会一直去厕所,通常的节奏是!喝水喝水喝水上厕所!喝水喝水喝水上厕所!虽然一直在触发,但是每隔一段时间只会执行一次操作,这就是函数节流!

  • 使用节流之时间戳版
//绿色基础版之时间戳版
function throttle(doSomething,wait){
    var _this,
        _arguments,
        initTime = 0;
    return function(){
        var now = +new Date();//将new date()转化为时间戳
            _this = this;
            _arguments = arguments;
        if(now - initTime>wait){
            doSomething.apply(_this,_arguments);
            initTime = now;
        }
    }
}
//触发onmousemove事件
xcd.onmousemove = throttle(doSomething,1000);

  • 使用节流之定时器版
//绿色基础版之定时器版
function throttle(doSomething,wait){
    var timeout;
    return function(){
        var _this = this;
            _arguments = arguments;
        if(!timeout){
            timeout = setTimeout(function(){
                timeout = null;
                doSomething.apply(_this,_arguments);
            },wait);
        };
    }
}
//触发onmousemove事件
xcd.onmousemove = throttle(doSomething,1000);

    同样,以上两个节流的绿色基础版也可以满足大多数需求场景啦!这两个版本有什么区别呢?时间戳版会在开始时立即执行一次,最后时间间隔内不再执行;定时器版开始时不执行,最后时间间隔内再执行一次。可以根据自己的实际需求选择合适的版本。

    当然,可能还有一些BT的产品会问你,能不能先立即执行一次,中间固定间隔时间执行,最后在执行一次呢?这就到了装B的时候了。像我这么牛X的前端,必须的啊,把两种合在一起就行了,双修什么的最喜欢了*@ο@*

  • 使用节流之双剑合璧版
//节流之双剑合璧版
function throttle(doSomething, wait) {
    var timeout, _this, _arguments,
        previous = 0;

    var later = function() {
        previous = +new Date();
        timeout = null;
        doSomething.apply(_this, _arguments)
    };
    var throttled = function() {
        var now = +new Date();
        //下次触发 doSomething 剩余的时间
        var remaining = wait - (now - previous),
            _this = this;
            _arguments = arguments;
         // 如果没有剩余的时间了
        if (remaining <= 0) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            doSomething.apply(_this, _arguments);
        } else if (!timeout) {
            timeout = setTimeout(later, remaining);
        }
    };
    return throttled;
}
//触发onmousemove事件
xcd.onmousemove = throttle(doSomething,1000);

深入理解函数防抖和节流,合理选择防抖或节流,能解决很多帕金森疾病,实乃出门旅行,居家生活之必备良品!OK就酱,我就是我,我瞅自己都上火!不定期分享一些前端知识点和面试点,喜欢点波关注呗!

参考:https://github.com/mqyqingfeng/Blog