zoukankan      html  css  js  c++  java
  • 函数节流和函数防抖

    从场景说起

    滑动到底部继续加载,是移动端很常见的一种场景。
    通常来说,我们会在对可滑动区域(一般是window)的scroll事件做监听,判断距离底部还有多远,如果距离底部较近,则发起HTTP请求,请求下一页的数据。
    很容易写出这样的代码:

    let page = 0;
    
    document.querySelector('.main').addEventListener('scroll', () => {
      scrollMore(this);
    })
    
    // 滑动获取更多内容
    function scrollMore(el) {
      if (getScrollTop(el) + getClientHeight() >= getScrollHeight(el) - 100) {
        fetch('http://api.jd.com/somethings/' + page++)
          .then(function(response) {
            console.log(response.json());
            // do something 把数据填充到页面上
          })
      }
    }
    
    function getScrollTop(el) { //取窗口滚动条高度
      return el.scrollTop;
    }
    
    function getClientHeight() { //取窗口可视范围的高度
      let clientHeight = 0;
      if (document.body.clientHeight && document.documentElement.clientHeight) {
        clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
      } else {
        clientHeight = (document.body.clientHeight > document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight;
      }
      return clientHeight;
    }
    
    function getScrollHeight(el) { //取文档内容实际高度
      return Math.max(document.body.scrollHeight, el.scrollHeight);
    } 
    

    但是这样很容易就发现一个问题,触发的scroll事件太频繁了,在一些低端机上,可能会卡顿。
    其实我们的判断没有必要这么频繁,用户的滑动操作是一段时间内不停触发的。
    我们希望在一小段时间内,只触发一次执行。

    函数节流

    这就是函数节流要做的事情,《JavaScript高级程序设计》中给了一个方法:

    function throttle (method, context) {
        clearTimeout(method.tId);
        method.tId = setTimeout(function () {
            method.call(context);
        }, 100)
    }
    

    这个代码的原理就是在多次执行的时候,清除上一次的timeout,如果时间间隔没有超过100ms,则又新建一个新的timeout,旧的则被丢弃。
    考虑一下,如果在一段时间内,每隔99ms触发一次,那么不停地清除上一次的timeout,函数将永远不会执行。
    我们更希望,每隔100ms,函数就执行一次,而不是像现在一样。
    重新思考这个问题。
    关键点有两个:

    1. 间隔
    2. 执行

    先来把函数封装一下,将节流函数return出来:

    function throttle1 (method, delay) {
        let timer = null;
    
        return function () {
          let
            context = this
          ;
          if (timer) clearTimeout(timer);
          timer = setTimeout(() => {
            method.call(context);
          }, delay)
        }
      }
    

    加上间隔判定:

    function throttle2 (method, delay) {
        let timer = null;
        let start;
        return function () {
          let
            context = this
            , current = Date.now()
          ;
    
          if (timer) clearTimeout(timer);
    
          if (!start) {
            start = current;
          }
    
          if (current - start >= delay) {
            method.call(context);
            start = current;
          } else {
            timer = setTimeout(() => {
              method.call(context);
            }, delay)
          }
        }
      }
    

    这样,基本上完成了一个throttle函数。

    函数防抖

    防抖的场景也比较常见。
    比如搜索时,监听用户输入,提供联想词;或者用户连续点击提交按钮的场景。
    说实话,我感觉《高级》那本书里的节流例子,就是一个防抖的版本。
    几乎可以拿来就用。
    我们还是做一个比较完善的版本。

    function debounce (method, delay) {
        let timeout = null;
        return function () {
          clearTimeout(timeout);
          timeout = setTimeout(() => {
            method.apply(this, arguments);
          }, delay);
        };
      }
    
  • 相关阅读:
    get(0)??
    抽象类中。。
    matlab函数
    unity_快捷键
    unity_ UI
    关于博客园使用
    survival shooter
    第七次团队作业:Alpha冲刺(3/10)
    第七次团队作业:Alpha冲刺(2/10)
    第七次团队作业:Alpha冲刺(1/10)
  • 原文地址:https://www.cnblogs.com/liuyongjia/p/9457199.html
Copyright © 2011-2022 走看看