JS的防抖与节流

定义

  • 节流(throttle): n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发
  • 防抖(debounce): n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发,只会执行最后一次

节流

<div>
        <h1>计数器<span>0</span></h1>
        <button>点我+1</button>
 </div>


let span = document.querySelector('span')
    let btn = document.querySelector('button')
    let count = 0

    btn.onclick = _.throttle(function(){
        //节流:目前的这个函数5s执行一次
        //假如这里面有很多的业务代码,可以给浏览器充分的时间去解析
        count++
        span.innerHTML = count
        console.log(1);
    },5000)

防抖(debounce)

    <p>请你输入你搜索的内容: <input type="text"></p>

let inp=document.querySelector('input')
inp.oninput=_.debounce(function(){
 console.log('ajax');
},1000)

应用场景

防抖在连续的事件,只需触发一次回调的场景有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

节流在间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚到底部监听
  • 搜索框,搜索联想功能

手写简单的节流与防抖

节流(throttle)

function throttle(fn, time) {
      var startTime = +new Date()//初始时间戳
      return function () {
        var timeout = (+new Date() - startTime) >= time//;//判断时间间隔是否大于传入的time值,返回布尔值
        if (timeout) {
          fn.apply(this)
          startTime = +new Date()//重新初始化时间戳
        }
      }
   }

//测试
  function test() {
      console.log('测试');
    }
    const throttleTest = throttle(test, 5000)
    window.addEventListener('scroll', throttleTest)

防抖(debounce)

<input type="text" id="inp">

     function getUserAction() {
            console.log(1);
        }
        inp.oninput = debounce(getUserAction, 1000);


function debounce(fn, wait) {
            var timeout
            return function () {
                clearTimeout(timeout)
                timeout = setTimeout(fn, wait)
            }
        }

 这就实现了一个简易的防抖,指定时间内重复触发函数只会执行一次。已经很好的解决了高频重复触发的问题,但因为直接重写了oninput函数,this与event均丢失了。

先解决this指向问题,正常在oninput函数中,this指向的应该是调用函数的对象,也就是inp,因为在debounce中返回了真正重写oninput的函数,形成了一个闭包,导致this丢失。指定this指向的方法有apply与call,用法差别只在参数,call需要的是一个数组,这里就用apply。

function debounce(func, wait) {
    var timeout;

    return function () {
        var context = this;

        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context)
        }, wait);
    }
}

 解决event参数,正常在oninput函数中有一个event,指向当前的事件对象。因为debounce函数返回的是一个匿名函数,可以通过arguments属性来获取参数,该属性是一个由函数参数组成的类数组。

修改后的debounce:

function debounce(func, wait) {
    var timeout;

    return function () {
        var context = this;
        var args = arguments;

        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context, args)
        }, wait);
    }
}

 

 

参考:链接:https://juejin.cn/post/7030787304696315918

posted @ 2022-06-24 11:46  长安·念  阅读(198)  评论(0)    收藏  举报