输入框监听例子

这是一个常见的事件监听功能,很多网站的搜索框需要通过输入文本框的内容实时检索数据

每输入一个字符就会触发一次函数执行,因此函数的执行频率很高;很可能内容还没输入完就已经触发函数执行。
然而实际上我们并不需要这么高频率的执行反馈,而且浪费浏览器性能,甚至可能牵涉后台请求而影响服务器性能;所以这也是性能优化的场景。

防抖(debounce)
针对上述场景,提出第一种解决思路:防抖
什么是防抖?
指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
效果:短时间内多次触发同个事件,只会执行一次函数。
实现:setTimeOut函数
// fn是事件触发执行的函数
// wait是指等待时长,在wait时间内多次触发函数只会被执行一次
// immediate是否立即执行,true表示wait秒内触发只会执行第一次触发;false表示wait秒内触发只会执行最后一次触发
function debounce(fn, wait = 1000, immediate = false) {
var timeout;
return function() {
let ctx = this;
let args = arguments;
if(timeout) clearTimeout(timeout);
if(immediate) {
let callNow = !timeout;
// wait秒后清除定时器
timeout = setTimeout(()=>{timeout = null;}, wait);
// 先执行函数
if(callNow) fn.apply(ctx, args)
}else {
// wait秒后执行fn
timeout = setTimeout(()=>{fn.apply(ctx, args)}, wait);
}
}
}

至此,输入框防抖实现了,采用非立即执行方式,确保获取到最新的输入框值,n秒内没有再次输入才会触发函数,否则重新倒计时n秒,直到n秒内没有再次输入的时候才会触发函数执行。
节流(throttle)
上面输入框例子中防抖的实现是n秒内不再输入则触发函数执行,然而加入我们一直保持n秒内输入,则将永远无法触发函数,或者实际场景下可能很长一段时间无法触发。

如果希望即使用户不停输入,也能够在某个时间间隔反馈(触发函数),因此有了第二种解决思路:节流
什么是节流?
指连续触发事件但是在 n 秒中只执行一次函数,所以节流稀释了函数执行的频率
效果:n秒内多次触发同个事件,只会执行一次函数,直到下一个n秒才会重新生效。
实现:setTimeOut函数
// fn是事件触发执行的函数
// wait是指间隔时长,在wait时间内多次触发函数只会被执行一次
// timeStamp: true时间戳版,false定时器版
function throttle(fn, wait = 1000, timeStamp = false) {
let previous = 0;
let timeout;
return function() {
let ctx = this;
let args = arguments;
if(timeStamp){
let now = Date.now();
if(now - previous > wait) {
fn.apply(ctx, args);
previous = now;
}
}else {
if(!timeout) {
timeout = setTimeout(()=>{
timeout = null;
fn.apply(ctx, args)
}, wait)
}
}
}
}

其它常见应用场景
-
滚动监听,返回顶部功能,即监听浏览器滚动事件,返回当前滚动条位置与顶部距离。可以采用节流方式,当滚动条滚动时以n秒的时间间隔获取当前位置与浏览器顶部距离。
-
页面resize事件
-
按钮提交事件
-
拖拽事件
-
...
总结
防抖和节流都是为了解决频繁触发某个事件造成的性能消耗,在用户体验允许的情况下减少性能浪费。
在项目中不乏应用场景,至于选用防抖还是节流来降低性能损耗,可根据项目实际需求而定。