【若川视野 x 源码共读】第25期 | 跟着underscore学防抖

82 阅读1分钟

学习路径:juejin.cn/post/684490…

防抖-在事件触发后n秒后执行回调函数,如果n秒内再次触发,则重新计算时间。

使用

鼠标事件:click、mousemove、mouseover

键盘事件:keydown、keyup

window事件:resize,scroll

<!DOCTYPE html>
<html lang="zh-cmn-Hans">

  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1">
    <title>debounce</title>
    <style>
      #container{
        width: 100%; height: 200px; line-height: 200px; text-align: center; color: #fff; background-color: #444; font-size: 30px;
      }
    </style>
  </head>

  <body>
    <div id="container"></div>
    <script src="debounce.js"></script>
  </body>

</html>
var count = 1;
var container = document.getElementById('container');

function getUserAction() {
    container.innerHTML = count++;
};


container.onmousemove = getUserAction;

代码

第一版:限定时间内不可重复触发

function debounce(fn,wait){
  var timeout;
  return function(){
    clearTimeout(timeout)
    timeout=setTimeout(fn,wait)
  }
}

container.onmousemove = debounce(getUserAction, 1000);1s内不触发

this

不使用debounce函数,getUserAction的this指的是div #container,但是debounce的this指向的是window对象,使用apply处理this的指向。

function debounce(fn,wait){
  var timeout;
  return function(){
  	var context=this;
    clearTimeout(timeout)
    timeout=setTimeout(fn.apply(context),wait)
  }
}

argument

不使用debounce函数,getUserAction传入e,会打印MouseEvent对象。但是使用debounce,getUserAction的e将打印为undefined。

function debounce(fn,wait){
  var timeout;
  return function(){
  	var context=this;
		var args=argument;
    clearTimeout(timeout)
    timeout=setTimeout(fn.apply(context,args),wait)
  }
}

返回值

如果getUserAction返回值,所以debounce需要返回值。

function debounce(fn,wait){
  var timeout;
	var result;
  return function(){
  	var context=this;
		var args=argument;
    clearTimeout(timeout)
    timeout=setTimeout(function(){
			result=fn.apply(context,args)
		},wait)
		return result
  }
}

立即执行

希望立即执行,在过n秒停止触发触发后再执行。而不是要等待n秒后,才能执行。

function debounce(fn,wait,immediate){
  var timeout;
	var result;
  return function(){
  	var context=this;
		var args=argument;
    if(timeout)clearTimeout(timeout)
    if(immediate){
      val callNow=!timeout   //表示已经执行
  		timeout=setTimeout(function(){
  			result=null
  		},wait)
			if(callNow){
				result=fn.apply(context,args)
			}
    }else{
      timeout=setTimeout(function(){
  			result=fn.apply(context,args)
  		},wait)
		}
		return result
  }
}

取消

希望有一个取消按钮,点击取消后,停止等待,可以理解触发。

function debounce(fn,wait,immediate){
  var timeout;
	var result;
  var debounced=function(){
  	var context=this;
		var args=argument;
    if(timeout)clearTimeout(timeout)
    if(immediate){
      val callNow=!timeout   //表示已经执行
  		timeout=setTimeout(function(){
  			timeout=null
  		},wait)
			if(callNow){
				result=fn.apply(context,args)
			}
    }else{
      timeout=setTimeout(function(){
  			result=fn.apply(context,args)
  		},wait)
		}
		return result
  }
  debounced.cancel={
		clearTimeout(timeout)
		timeout=null
  }
	return debounced
}