关于js函数防抖和回流的一些思考(闭包和定时器)

前言:
为啥要函数防抖和节流呢,因为像onmousemove ,或者按钮等等被用户频繁移动,点击等情况,造成代码一直在执行导致性能降低,所以用函数防抖和节流来限制在一定时间内函数所能执行的次数

举例


  

结果:一旦触碰到div并移动,就会一直触发,若还会发送情请求,则对性能影响极大。

防抖

什么是防抖?短时间内多次触发同一个事件,只执行最后一次,或者只在开始时执行,中间不执行.

(1)简单版

    const debounce = (func, wait, ...args) => {
      let timeout; //这里使用闭包来保存局部变量=>tip:  闭包保护的变量会一直保存在内存中但又不会 “污染” 全局的变量
      return function () {
        const self= this;
        if (timeout) clearTimeout(timeout);//当规定时间内最后一次触发的时候才会真正的执行,否则会被清除
        timeout = setTimeout(() => {
          func.apply(self, args)
        }, wait);
      }
    }

    content.onmousemove = debounce(count, 1000);

因为函数防抖和节流都不可避免用到闭包,又重新理解了下闭包

    function count() {
        let arr = [];
        console.log('start');
        for (var i=1; i<=3; i++) {  
            console.log('i:'+i);       //被保护的变量会一直保存在内存中,直到被释放
            arr.push(function () {     
                console.log('函数内的i:'+i);   //返回的函数只有被执行了才会执行,所以f1,f2,f3被执行时,i已经变成了4
                return i * i;
            });
        }
        return arr;
    }

    let results = count();
    let f1 = results[0];
    let f2 = results[1];
    let f3 = results[2];
    console.log(f1());
    console.log(f2());
    console.log(f3());            

运行结果:
关于js函数防抖和回流的一些思考(闭包和定时器)_第1张图片
(2)改进版
在上述简单版中,在一些特定的场合无法使用,比如一点击就需要立即执行的需求中

    function debounce(doSomething, wait, isImmediate) {
      let timeout;
      return function () {
          let _this = this,
              _arguments = arguments;
          clearTimeout(timeout);
          if (isImmediate) {
              let isTrigger = !timeout;
              timeout = setTimeout(function () {
                  timeout = null;  //在函数结束之后释放内存,并可以进行下一次执行
              }, wait);
              isTrigger && doSomething.apply(_this, _arguments);
          } else {
              timeout = setTimeout(function () {
                  doSomething.apply(_this, _arguments);
              }, wait);
          }
      }
  }

  function go() {
      console.log('666666666');
  }

  let d1 = document.getElementById('d1');

  d1.onclick = debounce(go, 500, true);//true为立即执行版,执行第一次点击,  false为执行最后一次的版本

关于定时器的思考:上述代码中,timeout 的值一般从1是开始(这里从2开始),number类型,再一次调用为2,一次增加,代表当前是第几个定时器 ,而timeout = null和clearTimeout是不一样的,赋值timeout 为null,只不过是清除了timer这个变量,清除了timer的内存占用,setTimeout还是存在的,清除定时器只能用clearTimeout(timeout)。

节流

节流是连续触发事件的过程中以一定时间间隔执行函数。节流会稀释你的执行频率,比如每间隔1秒钟,只会执行一次函数,无论这1秒钟内触发了多少次事件。
(1)立即执行版

    function throttle(doSomething,wait){
        let _this,
            _arguments,
            initTime = 0;
        return function(){
            let now = +new Date();//将new date()转化为时间戳
            _this = this;
            _arguments = arguments;
            if(now - initTime>wait){
                doSomething.apply(_this,_arguments);
                initTime = now;
            }
        }
    }
    let d2 = document.getElementById('d2');

    d2.onclick = throttle(go, 500);

(2)非立即执行版

function throttle(doSomething,wait){
    lettimeout;
    return function(){
        let _this = this;
            _arguments = arguments;
        if(!timeout){
            timeout = setTimeout(function(){
                timeout = null;
                doSomething.apply(_this,_arguments);
            },wait);
        };
    }
}

区别:

函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖靠清除定时器操作,只是在最后一次事件后或第一次才触发一次函数。

你可能感兴趣的:(js)