在前端开发过程中,会经常涉及到一些需要持续触发的事件,如:scroll,mousermove,resize,输入框监听,按钮提交等,频繁执行函数大大影响性能,利用防抖和节流可以防止一个函数被无意义的高频率调用。
防抖:当用户多次触发事件函数时,只触发最后一次操作的,其余的全部忽略掉;
节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数(避免事件在短时间内重复触发)
JavaScript版
1、鼠标移动--防抖示例
// 防抖:函数在触发事件后在n秒内函数只执行一次。如果在n秒内又触发了事件,则会重新计算函数执行时间。
<body>
<div id="content" style="height: 350px;line-height: 350px;text-align: center;background-color: #ccc;"></div>
</body>
<script>
let num = 1;
let content = document.getElementById("content");
function count() {
content.innerHTML = "防抖:" + num++;
}
content.onmousemove = debounce(count);
function debounce(fn, delay = 500) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
timer = setTimeout(fn, delay);
} else {
timer = setTimeout(fn, delay);
}
}
}
</script>
2、按钮点击事件--防抖示例
// 按钮连续点击,不会重复调用点击事件函数
<body>
<button id="content">防抖:0</button>
</body>
<script>
let num = 1;
let content = document.getElementById("content");
function count() {
content.innerHTML = "防抖:" + num++;
}
content.onclick = debounce(count);
function debounce(fn, delay = 200) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
timer = setTimeout(fn, delay);
} else {
timer = setTimeout(fn, delay);
}
}
}
</script>
3、鼠标移动--节流示例
// 节流:连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
// 如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。
<body>
<div id="content" style="height: 350px;line-height: 350px;text-align: center;background-color: #ccc;"></div>
</body>
<script>
let num = 1;
let content = document.getElementById("content");
function count() {
content.innerHTML = "节流:" + num++;
}
content.onmousemove = throttle(count);
function throttle(fn, delay = 1000) {
let valid = true
return function () {
if (valid) {
valid = false;
setTimeout(() => {
fn()
valid = true;
}, delay)
} else {
return;
}
}
}
</script>
Vue版
// 防抖函数: 频繁触发、输入框搜索
<template>
<div>
<input type='text' v-model='value' @keydown="handelChange">
</div>
</template>
<script>
export default {
data() {
return {
value: ""
};
},
methods: {
debounce(func, wait = 1000) {
let timeout;
return function (event) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.call(this, event);
}, wait);
};
},
handelChange(){
this.debounce(function (e) {
console.log(this.value);
});
}
}
};
</script>
// 节流函数:频繁触发、onrize,onscroll滚动条
<template>
<div class="scroll" ref="previewText" @scroll.passive="fnScroll">
</template>
<script>
export default {
data() {
return {
count: 0,
fnScroll: () => {},l
};
},
created() { this.fnScroll = this.fnThrottle(this.fnHandleScroll, 1000);
},
methods: {
fnHandleScroll(e) {
console.log("滚动触发了:" + this.count++, new Date());
},
fnThrottle(fn, delay, atleast) {
//节流函数
let timer = null;
let previous = null;
return function () {
let now = +new Date();
if (!previous) previous = now;
if (atleast && now - previous > atleast) {
fn();
previous = now;
clearTimeout(timer);
} else {
clearTimeout(timer);
timer = setTimeout(() => {
fn();
previous = null;
}, delay);
}
};
}
}
};
</script>