乐趣区

20190726前端笔记防抖和节流

防抖

为了避免一些监听事件为在自己预料的情况,频繁触发。or 在某些监听命令会频繁触发事件比如 resizemousemove 等等

未防抖 示例

       var count = 0,
          Elem = doc.getElementById('con')

        function appendCount(e) {console.log(e);
            
          Elem.innerHTML = count++
        }

        // 正常,没有防抖的情况下,直接监听执行
        Elem.addEventListener('mousemove', function() {appendCount()
        })

这会导致,只要鼠标移动,会导致 Eelm.innerHTML 不断改变。现在看起来好像没什么问题,如果是很多数据渲染或者请求几千条列表数据呢?

会导致浏览器不断回流和重绘。

那如何防抖呢??

触发 mousemove 时间后 1s 内,只有不在触发 mousemove 方法才会能执行appendCount()

var count = 0,
    Elem = doc.getElementById('con');
     
function debounce(fn, waitTime){
    // 定义定时器
     var timeoutFn = null;
     
     return function (){
          // 清空定时器
          clearTimeout(timeoutFn);
          // 重置定时器
          timeoutFn = (() => {fn.apply(this, arguments)
          },waitTime)
     }
}

function appendCount(){ELem.innerHTML=count++;}

Elem.addEventListener('mousemove', debounce(appendCount, 500))

防抖流程

  • mousemove触发, 触发debounce()`
  • 定义一个定时器 timeoutFn,返回执行内容为:清除当前timeoutFn 定时器( timeoutFn = null;),定义执行内容。

    // debounce() 返回内容
    function (){
          // 清空定时器
          clearTimeout(timeoutFn);
          // 重置定时器
          timeoutFn = (() => {fn.apply(this, arguments)
          },waitTime)
     }
  • mousemove 再触发,timeoutFn定时器再次清空,重新定义执行内容
  • 只有等到最后一次 mousemove,定时器没有被debounce() 清除 timeoutFn 定时器,最后执行 fn.apply(this, agruments);

节流

相对比防抖,我是这样理解节流的: 当我们想触发在 一段时间范围有且只触发一次 这样的事件,这样我们可以更节约我们的资源和网络请求。

就当上面的 AppendCount() 举例,我只想在 3s 内之能触发一次 事件AppendCount()

那么应该怎么处理呢?

var count = 0,
    Elem = doc.getElementById('con');

function throttle(fn,waitTime){
    var timeoutFn = null;
     
    return function () {
        // 如果存在 timeoutFn 定时器,则等待 timeoutFn 执行完成
        if(!timeoutFn){timeoutFn = (() => {
                // 置空定时器
                clearTimeout(timeoutFn)
                fn.apply(this, arguments)
            },waitTime)
        }     
    }
}

function appendCount(){ELem.innerHTML=count++;}

Elem.addEventListener('mousemove', throttle(appendCount, 3000))

这和防抖不同的是,是等待 timeoutFn 执行完成后,通过 clearTimeout(timeoutFn) 置空,那么在 3s 后才能再次执行timeoutFn

还有一个写法,和上面有一点不同,上面的是当在第 1s 触发 throttle,但是要在第 4s 才能执行appendCount。但是下面是 立即执行,当第 1s 触发throttle, 就执行appendCount, 然后在第 4s 后可以再次会发throttle

var count = 0,
    Elem = doc.getElementById('con');

function throttle(fn, waitTime){
    // 定义定时器、执行状态
    var timeoutFn = null,
        isRuning = false;
     
    return function () {
        // 如果不在执行状态
       if(!isRuning){
           // 开启执行状态
           isRuning = true;
           // 定义定时器
           timeoutFn =(() => {fn.apply(this, arguments);
              // 执行完成,关闭执行状态
              isRuning = false;
           },waitTime)
       }
    }
}

function appendCount(){ELem.innerHTML=count++;}

Elem.addEventListener('mousemove', throttle(appendCount, 3000))

参考

  • JavaScript 专题之跟着 underscore 学节流
  • JavaScript 专题之跟着 underscore 学防抖
退出移动版