js 节流函数

在性能优化实践中,遇到scroll事件,优先需要考虑节流。 节流函数顾名思义,就是要使密集频繁触发的函数,按照有规律有节制的过程去执行,那么背后的原理是什么?一步步实现吧。

1 最最最简单使用场景举例:监听屏幕滚动,添加回调函数,要怎么写呢?
var num = 0
window.onscroll = function () {

  console.log('回调函数执行' + (++num) + '次')
    
}
复制代码
效果如下

可以发现,随意滚动屏幕,回调函数就会执行很多次,也就是频繁的触发着回调函数,所以为了减少性能开销,要降低函数执行频率。
2 如果只让滚动事件结束后触发回调函数,该怎么做?
var num = 0
var timer = null
var cb = function(){
  console.log('回调函数执行' + (++num) + '次')
}
window.onscroll = function () {
  clearTimeout(timer)
  timer = setTimeout(() => {
    cb()
  }, 1000)
}
复制代码

可以看到结果是,在页面滚动结束的一秒后,控制台才会打印结果。
其实window绑定的滚动监听事件在页面滚动时候还是和上面一样的触发。只是用来控制台打印的回调函数,放在setTimeout中去执行。
滚动监听函数触发间隔远远小于setTimeout的一秒,所以回调函数cb还未来得及执行,就已经被下一次的滚动clearTimeout(timer)了。
只有在滚动结束的前一次触发,会生成一个setTimeout不会再被清除,也就在滚动结束后一秒执行了cb函数。
那么这么写有什么问题存在? timer直接被定义在了全局,应该避免。
var num = 0
var cb = function(){
  console.log('回调函数执行' + (++num) + '次')
}
var throttle = function (fn, delay) {
    var timer = null
    return function () {
        clearTimeout(timer);
        timer = setTimeout(function() {
            fn();
        }, delay);
    }
}
window.onscroll = throttle(cb, 1000)
复制代码
为什么这么写可以避免全局变量污染?仔细看,就是一个闭包。
window.onscroll 绑定的是 throttle(cb, 1000) ,即绑定的是传入参数为cb 和 1000,throttle执行后返回的函数。这个函数可以一直拿到父级作用域下的timer,而在window环境下无法拿到这个timer变量。也就避免了全局变量污染。
到目前为止,还只是解决了在滚动结束后触发回调函数这个问题。而这并不是节流。因为上述写法在不间断的滚动屏幕过程中,不会执行回调函数,只有在停止滚动后才会去执行。这显然不是节流。那么需要在滚动过程中,至少400ms就要触发一次传入的回调函数,要如何修改?
var num = 0
var cb = function(){
console.log('回调函数执行' + (++num) + '次')
}
var throttle = function (fn, delay, atleast) {
// 声明定时器
var timer = null
var previous = null
return function () {
  // 每次页面滚动时候都会生成新的时间戳
  var now = +new Date()
  // 如果是第一次滚动
  if ( !previous ) previous = now
  // 不断的滚动,直到时间间隔满足条件,执行回调函数,更新previous,清空定时器
  if ( atleast && now - previous > atleast ) {
    fn();
    previous = now
    clearTimeout(timer)
  // 不满足时间间隔条件,还是进函数中先清空上次的定时器
  // 并生成新的定时器,
  } else {
    clearTimeout(timer)
    timer = setTimeout(function() {
      fn()
    }, delay);
  }
 }
}
window.onscroll = throttle(cb, 1000, 400)
复制代码
运行结果如下图,在频繁滚动页面过程中,每隔400毫秒打印结果,滚动停止后一秒打印结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值