防抖和节流

820 阅读2分钟

通常应用在输入查询,滚动加载,抢票,窗口改变等应用场景。

防抖

一句话概括:高频函数连续调用时,空闲时间必须大于给定时间。

原理就是利用异步函数来延时执行。

首先实现结束边界版 (结束边界就是在空闲时间结束时执行) es6 版

// func 要防抖的函数
// wait 空闲时间
// flag boolean 开始边界 结束边界
function debounce(func, wait, flag){
  let timer = null;
  return function(){
    if(timer) clearTimeout(timer);
    timer = setTimeout(()=>func.call(this),wait);
  }
}

实现结束边界版 (结束边界就是在空闲时间结束时执行) es5 版

主要是异步函数牵涉到的执行上下文问题

// func 要防抖的函数
// wait 空闲时间
// flag boolean 开始边界 结束边界
function debounce(func, wait, flag){
  var timer = null;
  return function(){
    var self = this;
    if(timer) clearTimeout(timer);
    timer = setTimeout(function(){
      func.call(self)
    },wait);
  }
}

实现开始边界版 (开始边界就是在空闲时间开始时执行) es6

通过 flag 来开关这个功能

// func 要防抖的函数
// wait 空闲时间
// flag boolean 开始边界 结束边界
function debounce(func, wait, flag){
  let timer = null;
  return function(){
    if(timer) clearTimeout(timer);
    if(flag){
      // 开始边界
      // 在 timer === null 时立即执行函数
      // 同时开启延时函数 timer = null
      if(!timer){
        func.call(this)
      }
      timer = setTimeout(() => {
        timer = null
      }, wait);
    }else{
      // 结束边界
      timer = setTimeout(()=>func.call(this),wait);
    }
  }
}

节流

将连续执行优化为每隔一段时间执行

也就是说异步函数已经在执行,那么就不会开另外一个异步函数

我们来代码翻译这句话

function throttle (func, wait){
    var timer = null;
    return function(){
        var self = this;
        if(timer) return;
        timer = setTimeout(function(){
            func.call(self)
            timer = null
        }, wait);
    }
}

节流立即执行

function throttle(func, wait, flag){
  let timer = null
  return function(){
    if(timer) return;
    if(flag){
      func.call(this)
      timer = setTimeout(function(){
        timer = null
      }, wait);
    }else{
      timer = setTimeout(()=>{
        func.call(this)
        timer = null
      }, wait)
    }
  }
}

每隔地段时间执行一次

function throttle(func, wait){
  let previous = 0
  return function(){
    let now = +new Date()
    if(now - previous >= wait){
      func.call(this)
      previous = now
    }
  }
}

注意

通常防抖和节流函数是用在异步函数中的,所以 定义函数的地方 不能使用 箭头函数

例如例子中的 return function()

错误用法,无法获取被点击的对象

button.addEventListener('click', () => {
     this.classList.toggle('on');
});