防抖函數與節流函數

應用場景瀏覽器

實際工做中,咱們常常性的會經過監聽某些事件完成對應的需求,好比:app

  1. 經過監聽 scroll 事件,檢測滾動位置,根據滾動位置顯示返回頂部按鈕
  2. 經過監聽 resize 事件,對某些自適應頁面調整DOM的渲染(經過CSS實現的自適應再也不此範圍內)
  3. 經過監聽 keyup 事件,監聽文字輸入並調用接口進行模糊匹配
  4. ...

常規實現,以監聽 scroll 事件爲例函數

  咱們先來看一下scroll事件的觸發頻率oop

  

window.onscroll  = function () {
    //滾動條位置
    let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滾動條位置:' + scrollTop);
}

效果以下:性能

從效果上,咱們能夠看到,在頁面滾動的時候,會在短期內觸發屢次綁定事件。優化

咱們知道DOM操做是很耗費性能的,若是在監聽中,作了一些DOM操做,那無疑會給瀏覽器形成大量性能損失。this

下面咱們進入主題,一塊兒來探究,如何對此進行優化。spa

 

函數防抖3d

定義:屢次觸發事件後,事件處理函數只執行一次,而且是在觸發操做結束時執行。code

原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。

var timer;
    window.onscroll = function (e) {
        //防抖,當給timer賦值後,滾動又清空,直到中止滾動,執行timer函數
        if(timer){
          clearTimeout(timer)
        }  
        timer = setTimeout(function(){
          //執行事件函數  addLiScroll();
       let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條位置:' + scrollTop)

       timer = undefined;
 },200)
    }

 

 效果以下:滾動結束觸發事件

 

/**
 * 防抖函數
 * @param method 事件觸發的操做
 * @param delay 多少毫秒內連續觸發事件,不會執行
 * @returns {Function}
 */
function debounce(method,delay) {
    let timer = null;
    return function () {
        let self = this,
            args = arguments;
        timer && clearTimeout(timer);
        timer = setTimeout(function () {
            method.apply(self,args);
        },delay);
    }
}
window.onscroll = debounce(function () {
    let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    console.log('滾動條位置:' + scrollTop);
},200)

 

函數節流

定義:觸發函數事件後,短期間隔內沒法連續調用,只有上一次函數執行後,過了規定的時間間隔,才能進行下一次的函數調用。

原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。

let startTime = Date.now(); //開始時間
let time = 500; //間隔時間
let timer;
window.onscroll = function throttle(){
    let currentTime = Date.now();
    if(currentTime - startTime >= time){
        let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        console.log('滾動條位置:' + scrollTop);
        startTime = currentTime;
    }else{
        clearTimeout(timer);
        timer = setTimeout(function () {
            throttle()
        }, 50);
    }
}

 

防抖函數的封裝使用

/**
 * 節流函數
 * @param method 事件觸發的操做
 * @param mustRunDelay 間隔多少毫秒須要觸發一次事件
 */
function throttle(method, mustRunDelay) {
    let timer,
        args = arguments,
        start;
    return function loop() {
        let self = this;
        let now = Date.now();
        if(!start){
            start = now;
        }
        if(timer){
            clearTimeout(timer);
        }
        if(now - start >= mustRunDelay){
            method.apply(self, args);
            start = now;
        }else {
            timer = setTimeout(function () {
                loop.apply(self, args);
            }, 50);
        }
    }
}
window.onscroll = throttle(function () {
    let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    console.log('滾動條位置:' + scrollTop);
},800)

  封裝簡便的寫法

  

var time;
    window.onscroll = function (e) { //節流, 每隔多久執行一次
        if(!time){
          time = setTimeout(() => {
            //執行的事件             addLiScroll();
            time = undefined;
          }, 1000);
        }
        
    }
相關文章
相關標籤/搜索