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毫秒打印结果,滚动中止后一秒打印结果。

相关文章
相关标签/搜索