pfan123/Articles

防抖动(Debounce)和节流阀(Throttle)

Opened this issue · 0 comments

防抖动(Debounce)和节流阀(Throttle)

函数节流和函数防抖,两者都是优化高频率执行js代码的一种手段。常用于优化DOM 上有些事件是会频繁触发,比如mouseover、scroll、resize...。把 js 代码的执行次数控制在合理的范围,既能节省浏览器CPU资源,又能让页面浏览更加顺畅,不会因为js的执行而发生卡顿,这就是函数节流和函数防抖要做的事。

函数节流是指一定时间内js方法只跑一次。比如人的眨眼睛,就是一定时间内眨一次。这是函数节流最形象的解释。
函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。比如生活中的坐公交,就是一定时间内,如果有人陆续刷卡上车,司机就不会开车。只有别人没刷卡了,司机才开车。

函数节流

函数节流应用的实际场景,多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件。以下是监听页面元素滚动的示例代码:

var timer , canRun = true;
function throttle(delay){
   if(!canRun)return;

   canRun = false;
   clearTimeout(timer)
   timer = setTimeout(function(){
   		console.log(222)
   		canRun = true;
   }, delay || 200)
}

window.addEventListener("scroll", function(){
	console.log(1111)
	throttle(1000)
})

函数节流有两种形式:① 时间间隔内,起点执行,时间间隔中最后一次执行 ②时间间隔内,终点执行,时间间隔中最后一次执行

封装 throttle

/**
*
* @param fn {Function}   实际要执行的函数
* @param threshhold {Number}  执行间隔,单位是毫秒(ms)
* @param type {String}  是否第一次执行
* @return {Function}     返回一个“节流”函数
*/

function throttle(fn, threshhold, type) {

  // 记录是否可执行
  var isRun = true;

  // 定时器
  var timer;

  type = type || true;

  // 默认间隔为 200ms
  threshhold || (threshhold = 200)

  // 返回的函数,每过 threshhold 毫秒就执行一次 fn 函数
  return function () {

    // 保存函数调用时的上下文和参数,传递给 fn
    var context = this;
    var args = arguments;

    //第一次执行
    if(type && 'undefined' == typeof timer){
    	fn()  
    }

    if(!isRun)return;

    isRun = false;

    //保证间隔时间内执行
	timer = setTimeout(function () {
	   fn.apply(context, args)
	   isRun = true;
	}, threshhold)    

  }
}

//使用
document.addEventListener('mousemove', throttle(() => console.log(new Date().getTime()), 1000), false);

三、函数防抖

函数防抖的应用场景,最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。例:

var timer
function debounce(fn, delay){
	clearTimeout(timer)
	timer= setTimeout(fn, delay || 200)
}

input.addEventListener("keyup", function(){
	debounce(function(){console.log(22)}, 2000)
})

封装 debounce

/**
 *
 * @param fn {Function}   实际要执行的函数
 * @param delay {Number}  延迟时间,单位是毫秒(ms)
 *
 * @return {Function}     返回一个“防反跳 debounce”了的函数
 */

function debounce(fn, delay) {

  // 定时器,用来 setTimeout
  var timer

  // 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数
  return function () {

    // 保存函数调用时的上下文和参数,传递给 fn
    var context = this
    var args = arguments

    // 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn
    clearTimeout(timer)

    // 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作),
    // 再过 delay 毫秒就执行 fn
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, delay || 0)
  }
}

//使用
document.addEventListener('mousemove', debounce(() => console.log(new Date().getTime()), 1000), false);

ps: 此处精妙的地方就是,debounce()返回一个函数作为事件监听回调方法,实现 timer 共享,而不需全局定义 timer,减少污染全局变量

参考资料:
Javascript 的 Debounce 和 Throttle 的原理及实现
JavaScript函数节流和函数防抖之间的区别