在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如resize、scroll、mousemove等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。
var son=document.getElementById("son")
son.onmousedown = debounce (count, wait)
无论防抖还是节流,都要知道debounce是返回一个function,所以每次点击执行的是return里面的函数。所以timeout不会被重新声明。
因此执行到里面的function,调用时写debounce()()
1.防抖
- 思路:
每次触发事件时都取消之前的延时调用方法。
(1)立即执行版本
设定时间过了以后,timeout=null,callNow不为空,就可以执行新的操作了。如果还在设定时间之内,不会触发处理函数。几秒之后,这个timeout=null,可以重新触发处理函数了
function debounce2 (func, wait){ //防抖函数(立即执行)
let timeout;
return function(){
if(timeout) {
console.log("清理定时器")
clearTimeout(timeout)
}
let callNow =!timeout
timeout =setTimeout(()=>{
timeout=null
},wait)
if(callNow) {
func.apply(this)
}
}
}
(2)非立即执行版本
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则清掉原来的计时器,之前的计时器还没执行就被删掉,永远不会执行了
function debounce (func, wait){ //防抖函数(非立即执行),一段时间内多次操作化为一次,
let timeout;
return function(){
let context = this;
if(timeout) {
clearTimeout(timeout)
}
timeout=setTimeout(()=>{
func.apply(this)
},wait)
}
}
防抖技术仅靠传入延迟时间值的大小控制高频事件的触发频率,如果传入的延迟时间值比较大,那么就会出现一定的问题。例如当传入延迟时间为1000ms,那么当用户滚动速度大于1000ms/次时,则无论鼠标滚动多久都不会触发事件处理函数。因此防抖技术存在一定的缺陷,会不适用于某些场景,例如图片懒加载。这个时候节流就派上用场了。
2.节流
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
- 思路:
每次触发事件时都判断当前是否有等待执行的延时函数
(1)时间戳版本
function throttle(func, wait) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
函数会立即执行
(2)定时器版本
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}