函數的防抖和節流詳解

在前端開發的過程當中常常會遇到這樣的需求--經過鼠標的事件(mousemove,srcoll 等)連續觸發目標函數,若是不與後臺交互,在某些狀況下還說的過去,可是一旦與後臺交互,好比Ajax請求,那麼這個時候會對後臺形成很大的壓力,那麼如何才能避免這種情況呢?這裏就不得不請出今天要說的主角--函數的防抖和節流。前端

函數防抖與函數節流的區別:

函數節流: 不是讓函數不執行,而是讓函數在必定的時間內執行的次數減小一些服務器

函數防抖: 是超過必定的時間內執行一次,好比在mousemove事件中,鼠標中止移動後的1s後才執行。 若是還不明白,能夠移步的這裏本身體驗一把吧,哈哈!函數防抖和節流體驗閉包

函數防抖

先看一個例子,效果圖(從參考文章上扒下來的,說明問題就好)app

var num = 1;
var content = document.querySelector('.container');
addNum ();

function addPlus() {
    num++;
    content.innerHTML = num
}

document.onmousemove = addNum
複製代碼

函數防抖前的樣子,能夠想象若是addPlus裏面執行的不是簡單的計算,而是向服務器發送請求,能夠預見服務器要承擔多大的壓力。函數

若是使用防抖函數呢? 且看以下函數和效果圖post

document.onmousemove = debounce(addPlus,1000)

// 通常的防抖函數
function debounce(doSomething,wait){
    var timeout;//須要一個外部變量,爲加強封裝,因此使用閉包
    return function(){
        var _this = this,
            _arguments = arguments;
            // 關鍵,每次執行前都要先清空上一個timeOut,因爲速度特別快,
            // 因此在移動鼠標的時候,裏面的函數不會執行,直到當鼠標中止的時候,此時生成最後一個定時器
            // 並1秒後調用doSomething
        clearTimeout(timeout);
        // 再生成一個Timeout
        timeout = setTimeout(function(){
            doSomething.apply(_this,_arguments);
        },wait);
    }
};
複製代碼

當即執行版ui

function debounceIm(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);
        }
    }
}
document.onmousemove = debounceIm(addPlus,1000,true);

複製代碼

上述函數解析:this

若是isImmediate=true:spa

當鼠標第一次開始移動的時候,timeoutundefined,因此isTriggertrue,因此就會當即執行isTrigger&&doSomething.apply(_this,_arguments);而且timeout已是一個對象了,此時若是鼠標不停的移動就會致使isTriggerfalse,延時器一直被清空,直到停下來的時候過wait後執行timeout=null.net

若是isImmediate=false

就不說啦,跟第一次總結的同樣。

上述的效果圖以下:

函數節流

截留的目的不是不執行,而是讓函數執行的頻率變低,一般有兩種方案,一種是使用時間戳,一種是使用定時器

時間戳版

function trottle(doSomeThing,wait) {
    var _this,
        _arguments,
        initTime = 0;
    return function(){
        var now = +new Date();
            _this = this;
            _arguments = arguments;
            // 當間隔時間大於必定的時間後才觸發對應的函數
        if(now - initTime>wait){
            doSomeThing.apply(_this,_arguments);
            initTime = now;
        }
    }
}
document.onmousemove = trottle(addPlus,2000)

複製代碼

第一次mousemove的時候,會當即執行一次(由於第一次mousemove的時候now - initTime很大),以後就看時間間隔了

定時器(主要思想是經過mousemove不停建立新的延時器)

function throttle(doSomething,wait){
    var timeout;
    return function(){
        var _this = this;
            _arguments = arguments;
        if(!timeout){
            timeout = setTimeout(function(){
                // 主要是讓每次move的時候,使!timeout爲true
                timeout = null;
                doSomething.apply(_this,_arguments);
            },wait);
        };
    }
}
document.onmousemove = throttle(addPlus,2000)
複製代碼

這個方法的執行過程是這樣的:

第一次mousemove因爲timeoutundefined,因此會進入判斷並建立一個延時器,此時若是咱們當即不斷地mousemove!timefalse,就不會進入判斷,直到間隔wait時間段後,timeoutnull,此後再mousemove就會建立新的延時器,以此類推不斷地循環...

總結

這篇文章主要記錄一下本身對參考文章的思考過程,其中可能會有疏漏,還望你們指正~

參考文章:

相關文章
相關標籤/搜索