函数防抖,函数节流。详解!!!

本文详细探讨了JavaScript中的函数防抖(debounce)和函数节流(throttle)技术,阐述它们在处理频繁触发事件如搜索框实时请求、onmousemove、resize和onscroll等场景中的应用。通过实例讲解,解释了如何实现和优化函数防抖,包括防止全局变量污染、处理参数传递等问题,并介绍了函数节流的两种实现方式:时间戳判断和立即执行与延迟执行的结合。
摘要由CSDN通过智能技术生成

函数防抖:debounce

我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求, onmousemove, resize, onscroll等等,有些时候,我们并不能或者不想频繁触发事件, 咋办呢?这时候就应该用到函数防抖和函数节流了!

//应用场景,百度搜索框,监控文本框内容变化, 但是他不是时时刻刻监控,我们打完字后会等一下才自动搜索,可以自己取百度搜索体验一下

监控窗口发生变化的函数,如果不用函数防抖,
那么在拖动的过程中会触发很多次,这不是我们想看到了

  • 1.不添加函数防抖的window.onresize函数
    当你窗口拖动时,会连续触发很多次,输出很多次aaaa。
window.onresize = function () {
      console.log("aaaa");
    }

在这里插入图片描述

  • 2.简单封装过后的函数防抖,运行过后发现并没有什么卵用,只不过是延迟了一秒在重复上面的操作,自己试试 体验一下这个思考的过程。然后我们再继续优化
window.onresize = function () {
      debounce(function () {
        console.log("a");
      }, 1000)
    }
    /**
     * 函数防抖
     * callback,传入需要运行的函数
     * time ,多少时间后运行这个函数
     */
    function debounce(callback, time) {
      setTimeout(function () {
        callback();
      }, time)
    }
  • 3.我们再换一种方式处理,每次调用setTime之前我们把计时器id清除,这个时候就发现 一个粗糙的函数防抖已经做好了,但是这个有个缺点,定义了一个timer污染了全局变量,所以并不是完美的,还需要继续优化
window.onresize = function () {
      debounce(function () {
        console.log("a");
      }, 1000)
    }
    /**
     * 函数防抖
     * callback,传入需要运行的函数
     * time ,多少时间后运行这个函数
     */
    var timer;
    function debounce(callback, time) {
      clearTimeout(timer)
      timer = setTimeout(function () {
        callback();
      }, time)
    }
  • 4.继续优化,我们把timer定义在函数内部,利用闭包使变量私有。然后返回一个函数,在外部定义一个变量handle接收返回的函数,再在onresize触发事件中调用这个函数。这个时候你是不是觉得这个函数到这里就差不多了。是差不多了,这个时候已经可以应对绝大多数的情况了,但是还忽略了一点,没有考虑到传递参数的情况
//在函数内部返回一个新的函数叫高阶函数
var handle = debounce(function () {
      console.log("a");
    }, 1000)
    
window.onresize = function () {
      handle();
    }
/**
 * debounce函数防抖
 * callback,传入需要运行的函数
 * time ,多少时间后运行这个函数
 */
function debounce(callback, time) {
  var timer;
  return function () {
    clearTimeout(timer)
    timer = setTimeout(function () {
    callback();
    }, time)
  }
}
//debounce函数在这里的作用就是开启一个计时器,专供返回的函数使用,
  • 5.传参优化,窗口每一次改变的时候我要输出窗口的值。考虑到多个参数的情况,我们直接借用函数内部的arguments。
var handle = debounce(function (width) {
      console.log(width);
    }, 1000)
window.onresize = function () {
      handle(document.documentElement.clientWidth);
    }
/**
 * 函数防抖
 * callback,传入需要运行的函数
 * time ,多少时间后运行这个函数
 */
function debounce(callback, time) {
    var timer;
    return function () {
	   clearTimeout(timer) //清除之前的计时
	   var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
    	timer = setTimeout(function () {
    	callback.apply(null, args);
          //因为参数是个伪数组,而apply传递参数就是用数组传递,所以我们就正好利用这一点
          // 让apply帮忙,但是this指向不需要用到,所以我们给个null
        }, time)
      }
    }

利用刚刚写好的函数模拟百度搜索,自己试试哦

function debounce(callback, time) {
      var timer;
      return function () {
        clearTimeout(timer) //清除之前的计时
        var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
        timer = setTimeout(function () {
          callback.apply(null, args);
          //因为参数是个伪数组,而apply传递参数就是用数组传递,所以我们就正好利用这一点
          // ,让apply帮忙,但是this指向不需要用到,所以我们给个null
        }, time)
      }
    }
    var inp = document.querySelector("input");
    var handle = debounce(function (val) {
      console.log("搜索了" + val);
    }, 1000)
    inp.oninput = function () {
      handle(this.value)
    }

函数节流 throttle

保证一个时间段内只执行一次,函数节流有俩种做法,第一种是立即执行一次再说,第二种是等时间到了再执行第一次
  • 时间到了再执行第一次
/*函数节流 throttle
     *
     */
    function throttle(callback, time) {
      var timer;
      return function () {
        if (timer) {
          return;
        } //如果发现当前已经有计时了,啥都不做
        var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
        timer = setTimeout(function () {
          callback.apply(null, args);
          timer = null; //执行一次后timer必须清空,不然永远不会执行下一次了
        }, time)
      }
    }

    var handle = throttle(function () {
      console.log("a")
    }, 1000);
    handle()
    handle()
    handle()
    handle()
    handle()
    handle()
    handle()
    handle()
    handle()
   //连续调用handle函数,在1000毫秒内也只会执行一次。
  • 马上触发一次,下一下等一秒,利用时间戳
function throttle(callback, time) {
      var t;
      return function () {
        if (!t || Date.now() - t >= time) {
          callback.apply(null, arguments);
          t = Date.now()
        }
      }
    }
  • 俩种结合,传递第三个参数
function throttle(callback, time,immediately) {
      var t;
      var timer;
      return function () {
      if(immediately){
      if (!t || Date.now() - t >= time) {
          callback.apply(null, arguments);
          t = Date.now()
        }
      }
      if(!immediately){
      	if (timer) {
          return;
        } //如果发现当前已经有计时了,啥都不做
        var args = arguments; //保存当前函数参数数组,把参数带到setTimeout里面需要执行的函数。这里也有一点闭包的感觉
        timer = setTimeout(function () {
         callback.apply(null, args);
         timer = null; //执行一次后timer必须清空,不然永远不会执行下一次了
        }, time)
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值