防抖节流

186 阅读1分钟

防抖

  • 触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
  • 每次触发事件时都取消之前的延时调用方法
function showTop() {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    console.log('滚动条位置:' + scrollTop);
}
let timer;
function handle() {
    if (timer) {
        window.clearTimeout(timer);
    }
    timer = setTimeout(showTop, 200);
}
window.onscroll = handle;
  • 闭包写法
function debounce(fn,delay){
    let timer = null //借助闭包
    return function() {
        if(timer){
            clearTimeout(timer) 
        }
        timer = setTimeout(fn,delay)
    }
}
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = debounce(showTop,1000)

节流

  • 高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

  • 每次触发事件时都判断当前是否可以执行

function showTop() {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    console.log('滚动条位置:' + scrollTop);
}
let flag = true;
function handle() {
    if (!flag) {
        return;
    } else {
        flag = false;
        setTimeout(() => { showTop(); flag = true; }, 500)
    }
}
window.onscroll = handle;
  • 闭包写法
function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           return false 
       }
       // 工作时间,执行函数并且在间隔期内把状态位设为无效
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}
/* 请注意,节流函数并不止上面这种实现方案,
   例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
   也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
    */

// 以下照旧
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000)