JavaScript之函数节流(throttle)

前端菜鸟一只,查阅了一些资料,大概明白了什么是函数节流


是什么?

就是让一个函数无法在很短的时间间隔内连续执行,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。

为什么?

浏览器中某些计算和处理比其他要昂贵的多。例如,DOM操作比非DOM交互需要更多的内存和CPU时间。连续尝试很多DOM操作会导致浏览器挂起甚至崩溃。比如:重新调整浏览器窗口大小(resize),浏览器页面滚动(scroll),鼠标移动(mousemove)。也就是说用户在触发这些浏览器操作的时候,如果脚本里面绑定了对应的事件处理方法,这个方法就不停的触发。

应用场景

如果函数节流根据应用场景具体细分,还分两种。

  • 就是对于一定时间段的连续的函数调用,只让其执行一次回调函数。就是网上说的函数防抖(debounce)。

    • 每次 resize/scroll 触发统计事件
    • 文本输入的验证(连续输入文字后发送 AJAX 请求进行验证,验证一次就好)
  • 让一个函数不要执行得太频繁,减少一些过快的调用来节流。我们需要间隔一定时间触发回调来控制函数调用频率就是网上说的函数节流(throttle)。

    • DOM 元素的拖拽功能实现(mousemove)
      射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
    • 计算鼠标移动的距离(mousemove)
    • Canvas 模拟画板功能(mousemove)
    • 搜索联想(keyup)
    • 监听滚动事件判断是否到页面底部自动加载更多:给 scroll 加了 debounce 后,只有用户停止滚动后,才会判断是否到了页面底部;如果是 throttle 的话,只要页面滚动就会间隔一段时间判断一次。

简单实现

  var timer;
  function throttle(){
    if(timer){
      clearTimeout(timer);
      console.log('3');
    }
    timer=setTimeout(function(){
      console.log('函数防抖')
    },1000);
  }
  for(var i=0;i<10;i++){
  console.log("1");
  throttle();
  console.log('2');
}

上面的代码其实就是一个函数防抖,只执行最后一次。

  • 首先输出1,然后第一次调用函数,timer为undefined,所以不执行if语句,创建一个定时器,1秒后输出‘函数防抖’,timer有值,输出2,-
  • 但是马上又循环了一遍,输出1,这回timer有值,但是清除了原先的定时器,输出3,所以计时要重来,又创建一个,1秒后输出‘函数防抖’,timer有值,输出2
  • 接下来几步和第二步相同,到最后一次throttle()函数调用的时候,没有再清除timer定时器的机会了,所以一秒后输出‘函数防抖’。

接下来我们对整体进行封装

  function throttle(fn, delay) {
      var timer = null;
      return function () {
        clearTimeout(timer);
        timer = setTimeout(function () {
          fn(arguments)}, delay);
      }
    }

    function fn() {
      console.log("函数防抖");
    }
    var fn2 = throttle(fn, 1000);
    fn2();
    fn2();
    fn2();

然后我们再次改进变成函数节流,可以隔断时间触发回调函数

var throttle = function (fn, delay, atleast) {
    var timer = null;
    var previous = null;

    return function () {
        var now = +new Date();

        if ( !previous ) previous = now;

        if ( now - previous > atleast ) {
            fn();
            // 重置上一次开始时间为本次结束时间
            previous = now;
        } else {
            clearTimeout(timer);
            timer = setTimeout(function() {
                fn();
            }, delay);
        }
    }
};

参考资料:函数节流详解

推荐阅读更多精彩内容