美文网首页
防抖And节流

防抖And节流

作者: 有一种感动叫做丶只有你懂 | 来源:发表于2020-07-18 15:33 被阅读0次
1.防抖(debounce )

防抖的原理就是:你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,我才执行,真是任性呐!

第一版

    var count = 1;
    var container = document.querySelector('.container');
    function getUserAction() {
      console.log(this);//指向Window对象
      container.innerHTML = count++;
    }
    function debounce (){
      var timeout
      return function(){
          if (timeout) clearTimeout(timeout);
          timeout = setTimeout(func, wait);
      }
    }
    container.onmousemove = debounce(getUserAction, 1000);

我们可以看到getUserAction函数的this指向的是window对象,如果我们想指向<div class="container" ></div>我们该如何做呢?
第二版

   var count = 1;
   var container = document.querySelector('.container');
   function getUserAction() {
      console.log(this); //指向 <div class="container" ></div>
      container.innerHTML = count++;
    }

    function debounce(func, wait) {
      var timeout, context;
      return function () {
        context = this;
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this), wait);
      };
    }
    container.onmousemove = debounce(getUserAction, 1000);

我们利用apply方法改变了this的指向,从而getUserAction方法可以正确指向调用的的对象,那么问题又来了,我们在使用js操作dom元素的时候,函数会给我传一个事件对象,在我们第二版的函数中,如果直接输出参数,会看到输出undefined,想输出时间对象,我们应该如何做呢?
第三版

 var count = 1;
    var container = document.querySelector('.container');

    function getUserAction(e) {
      console.log(this); //指向 <div class="container" ></div>
      console.log(e); //输出事件对象
      container.innerHTML = count++;
    }

    function debounce(func, wait) {
      var timeout, context, args;
      return function () {
        context = this;
        args = arguments;
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this, arguments), wait);
      };
    }
    container.onmousemove = debounce(getUserAction, 1000);

这个时候,代码已经很是完善了,但是为了让这个函数更加完善,我们接下来思考一个新的需求。
这个需求就是:
我不希望非要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行。
想想这个需求也是很有道理的嘛,那我们加个 immediate 参数判断是否是立刻执行。
第四版(立即执行)

  var count = 1;
    var container = document.querySelector('.container');

    function getUserAction(e) {
      console.log(this); //指向 <div class="container" ></div>
      console.log(e); //输出事件对象
      container.innerHTML = count++;
    }

    function debounce(func, wait, immediate) {
      var timeout, context, args;
      return function () {
        context = this;
        args = arguments;
        if (timeout) clearTimeout(timeout);
        if (immediate) {
          var callnow = !timeout;
          console.log(callnow);
          timeout = setTimeout(() => {
            timeout = null;
          }, wait);
          if (callnow) {
            func.apply(this, args);
          }
        } else {
          timeout = setTimeout(() => func.apply(this, arguments), wait);
        }
      };
    }
    container.onmousemove = debounce(getUserAction, 1000, true);
image.png
从图中可以看出立即执行非立即执行函数的原理区别在于:
立即执行函数:timeout为undefined,所以 callnow第一次为true,当用户一直移动鼠标的时候,callnow都为false,当用户停止移动鼠标的时候,以下代码执行,将timeout变为null,所以当用户再次移动鼠标的时候,
timeout变为null,callnow又会变为true,
 timeout = setTimeout(() => {
            timeout = null;
          }, wait);
2.节流

节流的原理很简单:
如果你持续触发事件,每隔一段时间,只执行一次事件。
根据首次是否执行以及结束后是否执行,效果有所不同,实现的方式也有所不同。
我们用 leading 代表首次是否执行,trailing 代表结束后是否再执行一次。
关于节流的实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器。
时间戳

function throttle(func, wait) {
      var previous = 0;
      return function () {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
          func.apply(this, arguments);
          previous = now;
        }
      };
    }

定时器

 function throttle(func, wait) {
      var timeout;
      return function () {
        var context = this;
        if (!timeout) {
          timeout = setTimeout(() => {
            func.apply(context);
            timeout = null;
          }, wait);
        }
      };
    }

最后贴上大神链接
节流
防抖

相关文章

网友评论

      本文标题:防抖And节流

      本文链接:https://www.haomeiwen.com/subject/quvxkktx.html