防抖
为了避免一些监听事件为在自己预料的情况,频繁触发。or 在某些监听命令会频繁触发事件比如
resize
、mousemove
等等
未防抖 示例
var count = 0,
Elem = doc.getElementById('con')
function appendCount(e) {console.log(e);
Elem.innerHTML = count++
}
// 正常,没有防抖的情况下,直接监听执行
Elem.addEventListener('mousemove', function() {appendCount()
})
这会导致,只要鼠标移动,会导致 Eelm.innerHTML 不断改变。现在看起来好像没什么问题,如果是很多数据渲染或者请求几千条列表数据呢?
会导致浏览器不断回流和重绘。
那如何防抖呢??
触发 mousemove
时间后 1s 内,只有不在触发 mousemove
方法才会能执行appendCount()
。
var count = 0,
Elem = doc.getElementById('con');
function debounce(fn, waitTime){
// 定义定时器
var timeoutFn = null;
return function (){
// 清空定时器
clearTimeout(timeoutFn);
// 重置定时器
timeoutFn = (() => {fn.apply(this, arguments)
},waitTime)
}
}
function appendCount(){ELem.innerHTML=count++;}
Elem.addEventListener('mousemove', debounce(appendCount, 500))
防抖流程
-
mousemove
触发, 触发
debounce()` -
定义一个定时器
timeoutFn
,返回执行内容为:清除当前timeoutFn
定时器(timeoutFn = null;
),定义执行内容。// debounce() 返回内容 function (){ // 清空定时器 clearTimeout(timeoutFn); // 重置定时器 timeoutFn = (() => {fn.apply(this, arguments) },waitTime) }
- 当
mousemove
再触发,timeoutFn
定时器再次清空,重新定义执行内容 - 只有等到最后一次
mousemove
,定时器没有被debounce()
清除timeoutFn
定时器,最后执行fn.apply(this, agruments);
节流
相对比防抖,我是这样理解节流的: 当我们想触发在
一段时间范围有且只触发一次
这样的事件,这样我们可以更节约我们的资源和网络请求。
就当上面的 AppendCount()
举例,我只想在 3s 内之能触发一次
事件AppendCount()
。
那么应该怎么处理呢?
var count = 0,
Elem = doc.getElementById('con');
function throttle(fn,waitTime){
var timeoutFn = null;
return function () {
// 如果存在 timeoutFn 定时器,则等待 timeoutFn 执行完成
if(!timeoutFn){timeoutFn = (() => {
// 置空定时器
clearTimeout(timeoutFn)
fn.apply(this, arguments)
},waitTime)
}
}
}
function appendCount(){ELem.innerHTML=count++;}
Elem.addEventListener('mousemove', throttle(appendCount, 3000))
这和防抖不同的是,是等待 timeoutFn
执行完成后,通过 clearTimeout(timeoutFn)
置空,那么在 3s 后才能再次执行timeoutFn
还有一个写法,和上面有一点不同,上面的是当在第 1s 触发 throttle
,但是要在第 4s 才能执行appendCount
。但是下面是 立即执行
,当第 1s 触发throttle
, 就执行appendCount
, 然后在第 4s 后可以再次会发throttle
var count = 0,
Elem = doc.getElementById('con');
function throttle(fn, waitTime){
// 定义定时器、执行状态
var timeoutFn = null,
isRuning = false;
return function () {
// 如果不在执行状态
if(!isRuning){
// 开启执行状态
isRuning = true;
// 定义定时器
timeoutFn =(() => {fn.apply(this, arguments);
// 执行完成,关闭执行状态
isRuning = false;
},waitTime)
}
}
}
function appendCount(){ELem.innerHTML=count++;}
Elem.addEventListener('mousemove', throttle(appendCount, 3000))
参考
- JavaScript 专题之跟着 underscore 学节流
- JavaScript 专题之跟着 underscore 学防抖