Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
pfan123 opened this issue Jun 3, 2017 · 0 comments
Open

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

pfan123 opened this issue Jun 3, 2017 · 0 comments
Labels

Comments

@pfan123
Copy link
Owner

pfan123 commented Jun 3, 2017

防抖动(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函数节流和函数防抖之间的区别

@pfan123 pfan123 added the web label Jun 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant