概念
函数防抖和函数节流,两者都是优化高频率执行js代码的一种手段。
如:浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能
为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用 防抖(debounce) 和 节流(throttle) 的方式来减少调用频率
定义
防抖 = 回城
节流 = 技能
防抖:就是一定时间内,只会执行最后一次任务;
-
n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
-
将多次高频操作优化为只在最后一次执行
使用场景:
- 用户输入,只需再输入完成后做一次输入校验即可。
- 防止用户多次提交表单,在短时间内频繁操作同一按钮而导致出现异常情况
- 滚动条、 resize 、拖拽 事件,通常只执行最后一次
.
节流:就是一定时间内,只执行一次 ;
-
n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
-
将高频操作优化成低频操作
使用场景:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能
.
例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数:
- 防抖,不管调动多少次方法,在2s后,只会执行一次
- 节流,每隔 500ms 就执行一次
防抖
<button id="debounce">点我防抖!</button>
<script>
$('#debounce').on('click', debounce());
function debounce() {
let timer; // 使用闭包,多次调用都能访问到同一个变量,而不是生成新的变量
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
// 需要防抖的操作...
console.log("防抖成功!");
}, 500);
}
}
</script>
按钮点击时,只有在用户点击后一段时间内没有再次点击时才触发对应操作:
函数防抖的应用场景,最常见的就是页面滚动条监听的例子,来进行解析:
let timer;
window.onscroll = function () {
clearTimeout(timer);
timer = setTimeout(function () {
//滚动条位置
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}, 200)
}
防抖函数的封装使用
// 防抖函数
function debounce(fn,delay) {
let timer;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this,arguments);
},delay);
}
}
window.onscroll = debounce(function () {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
},200)
// jq
$(window).on('scroll', debounce(function () {
console.log("防抖成功!");
}, 200))
节流
<button id="throttle">点我节流!</button>
<script>
$('#throttle').on('click', throttle());
function throttle(fn) {
let flag = true;
// 使用闭包,方法多次调用都能访问到同一个变量,而不是生成新的flag变量
return function () {
if (!flag) { return; }
flag = false;
setTimeout(() => {
console.log("节流成功!");
flag = true;
}, 1000);
};
}
</script>
函数节流应用的实际场景,根据文本框中输入的内容自动请求后台数据。
节流函数的封装使用
<input type="text" value="" id="input">
<script>
// 节流函数
function throttle(fn, delay) {
let flag = true;
return function () {
if (!flag) { return; }
flag = false;
setTimeout(() => {
fn.apply(this, arguments);
flag = true;
}, delay);
}
}
$('#input').on('keyup', throttle(function () {
console.log($(this).val());
// ajax后台请求....
}, 1000));
</script>