我们在对窗口的resize、scroll进行事件监听时,可能会导致事件处理函数被无限制调用,这样做会增加浏览器负担,如果事件处理函数有AJAX的话会造成无限次请求,给服务器也带来了负担。
如下例
var i = 1;
window.onscroll = function(){
console.log('函数执行'+i++);
//.....执行请求
}
//控制台打印结果
debounce.html:18 函数执行2
debounce.html:18 函数执行3
debounce.html:18 函数执行4
debounce.html:18 函数执行5
debounce.html:18 函数执行6
debounce.html:18 函数执行7
debounce.html:18 函数执行8
debounce.html:18 函数执行9
debounce.html:18 函数执行10
debounce.html:18 函数执行11
debounce.html:18 函数执行12
debounce.html:18 函数执行13
debounce.html:18 函数执行14
debounce.html:18 函数执行15
可以看到,我们只拉了一下滚动条,事件处理函数就被触发了15次 这里的我们可以采用防抖(debounce)
和节流(throttle)
的方式来减少调用频率,同时又不影响实际效果。
基于上面出现的问题我们可以采用这样的方式解决 当第一次触发事件函数时,我们并不让他立即执行,而是给出有个延迟时间(delay
)
delay
内没有再次事件,那么就执行函数delay
内再次触发滚动事件,那么当前的计时取消,重新开始计时这样就解决了一直触发某事件造成事件函数一直被调用的问题
代码实现
function debounce(fn,delay) {
var timeout = null;
return function() {
//如果在时间范围内触发了函数则重新计时
if(timeout !== null) clearTimeout(timeout);
timeout = setTimeout(fn, delay);
}
}
// 处理函数
function handle() {
console.log('函数执行'+i++);
}
//滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
//控制台打印
函数执行1
debounce.html:32 函数执行2
debounce.html:32 函数执行3
debounce.html:32 函数执行4
防抖应用之【JS实现懒加载】 在1S内触发的事件,其事件处理函数只执行一次
节流,可以简单理解为节约流量,比如用户一直触发按钮点击事件,而事件处理函数执行的是发送短信验证码逻辑,此时后台没有经过任何处理的话想想有多恐怖。 节流使得短期内触发大量事件,那么函数在执行一次后,该函数在指定的时间内都不工作,直到过了那个时间段才重新生效。
代码实现
btn.onclick = throttle(function(){console.log('3秒发送验证码')},3000)
function throttle(fn,delay){
let status = true //标识执行状态
return function() {
if(!status){
//休息中,停止执行
return false
}
// 工作时间,执行函数并且在间隔期内把标识设为无效
status = false
setTimeout(() => {
fn()
//处理函数执行完毕后,开放调用
status = true;
}, delay)
}
}
函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。