一、采用防抖和节流的必要性
在单位时间内,有些事件的触发频率会很高,比如scroll、resize、refresh、input框实时输入校验,这些情况会导致服务器请求跟不上,浏览器页面出现卡顿现象,同时给服务器造成负担,此时采用debounce(防抖)和throttle(节流)减少单位时间内的服务器请求次数,提升用户体验效果。
二、debounce(防抖)
简单说就是给事件设置一个时间段,如果这个函数在这个时间段内没有再次触发,就会执行一次,如果在这个设定时间到来之前再一次触发了事件,就重新开始计时,这个例子中只有当停止触发事件的1000毫秒后才会执行一次函数。
/*
* fn [function] 需要防抖的函数
* delay [number] 毫秒,防抖期限值
*/
function debounce(fn,delay){
let timer = null //借助闭包
return function() {
if(timer){
clearTimeout(timer) //进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时
timer = setTimeOut(fn,delay)
}else{
timer = setTimeOut(fn,delay) // 进入该分支说明当前并没有在计时,那么就开始一个计时
}
}
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
写完会发现其实 time = setTimeOut(fn,delay)
是一定会执行的,所以可以稍微简化下:
function debounce(fn,delay){
let timer = null //借助闭包
return function() {
if(timeout !== null) clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
思考:
防抖的含义就是在某个时间段内如果不停止持续的触发事件,就永远不会执行函数,但如果我们期望的效果是即使在一个时间段内持续的触发事件也能在某个时间间隔后触发一次事件呢?这个时候节流可以帮我们实现这样的效果
三、throttle(节流)
当持续触发事件时,保证一定时间段内只调用一次事件处理函数,下图。
function throttle(fn,delay){
let valid = true
return function() {
if(!valid){
return false
}
valid = false
setTimeout(() => {
fn()
valid = true;
}, delay)
}
}
function showTop () {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000)
这种效果就是,即使一直在滚动,也会每间隔一秒输出滚动条的位置