防抖和节流

266 阅读2分钟

节流和防抖

节流(throttle)和防抖(debounce)不是js语法层面的概念,也不属于特定属于js这门语言。它其实一个工程优化的自然产物。

它们的本质是:用来对函数的调用做降频(降低单位时间内被调用的次数)处理。

在js的语境,可以抽象一下:当一个函数被以较高的频率调用时(在极短的时间内被调用了多次),出于某些原因的考虑,我们希望降低它实际被执行的频率。

这个限制的策略有两种:防抖(debounce) , 节流(throttle)

为什么要降频

一个原因:性能优化。

举个例子:在实现鼠标跟随效果时,要给mousemove添加事件监听函数,假设伪代码如下:

const fn = () => { console.log(Date.now(),'鼠标移动了,我就执行')}
dom.addEventListener('mousemove',fn)
复制代码

当鼠标移动时,fn这个函数就会以一个非常高的频率(本机测量 1s内执行 ~ 120次)调用。如果这个函数每秒调用20次也能满足页面效果的话,那这些额外的高频调用就是没有意义的。

类似的例子还有:搜索建议框。

降频两种策略

防抖(debounce): 连续高频调用函数,函数执行1次(看具体的实现细节)

节流(throttle): 连续高频调用函数,函数按指定频率(低频)执行多次

它们又细分立即执行版,非立即执行版,混合版

防抖代码

立即执行版


function debounce_callnow(f,t=3000){
   var time = null  
   return function(){    
     if(!time){      
       f();    
     } else {      
         console.log("不要着急,等3s后再调用才有效")    
     }    
     clearTimeout(time)    
     time = setTimeout(()=>{ 
        time = null;    
     },t)
 }
         
 const fn = () => { console.log(Date.now(),'鼠标移动了,我就执行')}

 var  f1 = debounce_callnow(fn)
 document.addEventListener('mousemove',fn)
复制代码

非立即执行版

function debounce_callend(f,t=3000){
  let time = null
  return ()=>{
    if(time) {
      clearTimeout(time);
      console.log('不是立即执行的,等3s后看结果');
    }
    time = setTimeout(()=>{
      f();
    },t)
  }
}
复制代码

混合版本

function debounce_callboth(f,t=3000){
  let time = null
  return ()=>{
    if(!time){
      f();
    }
    clearTimeout(time)
    time = setTimeout(()=>{
      time = null;
      f();
    },t)
  }
}
复制代码

开发中的应用

场景

  • 节流:搜索建议框; onScroll事件处理
  • 防抖:搜索建议框; 记录当前滚动条的位置

实施: