1

函数防抖

适用场景:

  • 按钮提交:防止多次提交按钮,只执行最后提交的一次
  • 搜索框联想:防止联想发送请求,只发送最后一次输入

简便方法

函数防抖的指导思想是:某些代码可以在没有间断的情况下重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔后执行代码。当第二次调用该函数的时候,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行过了,这个操作没有意义。然而,如果前一个定时器尚未执行,其实就是替换为一个新的定时器,目的是只有在执行函数的请求停止了一段时间后才执行。

上代码:

    function debounce(method,context){
        clearTimeout(method.tId);            //{1}
        method.tId = setTimeout(function(){
            method.call(context);            //{2}
        },100);
    }

debounce方法接收两个参数:要执行的函数及在哪个作用域中执行。{1}首先清除之前设置的任何定时器,定时器ID是储存在函数的tId属性中的。定时器代码{2}使用call来确保方法在适当的环境中执行。如果没有给出第二个参数,那么就在全局作用域内执行该方法。

传入延时参数

关于防抖函数的写法,网上还看到另一种方法,可以传入延时时间作为参数,使用了闭包,但是大同小异。
原文在这里

    function debounce(method,delay){
        var timer=null;
        return function(){
            var context=this, args=arguments;
            clearTimeout(timer);
            timer=setTimeout(function(){
                method.apply(context,args);
            },delay);
        }
    }

立即执行

有时候希望函数能够立即执行,然后间隔n秒之后才能被再次触发,这种就很适合用在给按钮做幂等的场景。

function debounce(method, delay){
    var timer=null
    return function(){
        var context=this, args=arguments, callNow = !timer;
        clearTimeout(timer);
        timer=setTimeout(function(){
            timer = null;
        },delay);
        if(callNow) method.apply(context,args);
    }
}

函数节流

适用场景:

  • 拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
  • 缩放场景:浏览器resize

浏览器的DOM操作比起非DOM交互需要更多的内存和cpu时间,连续过多的DOM操作可能会导致浏览器挂起甚至崩溃。比如使用onresize,onscroll这些可能会被连续触发的事件的时候,如果事件处理程序中进行了过多地DOM操作,可能就会使得浏览器崩溃。而为了绕开这个问题,可能就需要使用到函数节流。
比如:

function resizeDiv(){          //在窗口尺寸改变的时候,调整div的高度
    var div = document.getElementById("myDiv");
    console.log(div.offsetWidth);
    div.style.height = div.offsetWidth + "px";
}
window.onresize = function(){
    resizeDiv();
}

上面的代码在我简单的拉伸窗口的时候被连续执行了,如果是更复杂的DOM操作,很可能使得浏览器崩溃。其实我想要的只是在我改变完窗口大小后,再调整一次myDiv的高度。

使用时间差

在开始处多设置了一个开始时间,然后在每次调用的时候判断当前时间是否有超过预设的时间间隔,如果超过了,就立即执行一次事件处理函数,然后再将当前时就按记录下来,如此往复。
代码如下:

  function throttle(method, duration){
    var begin=new Date();       //{1}
    return function(){
        var context=this, args=arguments, current=new Date();
        if(current-begin>=duration){        //{2}
             method.apply(context, args);
             begin=current;
        }
    }
}

使用定时器

还可以使用定时器来实现。

function throttle(method, duration) {
  var timer;
  return function () {
    var context = this, args = arguments;
    if (!timer) {
        timer = setTimeout(function () {
            method.apply(context, args);
            timer = null;
      }, duration)
    }

  }
}

以window.onresize为例,不直接执行事件处理函数了。

    window.onresize = throttle(resizeDiv, 1000);

这样,多数情况下,用户察觉不到变化,但能够给浏览器节省很多计算。


这个少年有点热丶
363 声望12 粉丝

[链接]