防抖
为了避免一些监听事件为在自己预料的情况,频繁触发。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))