我有一个牛逼的防抖,你要不要学

在开发中,我们可能碰到这样的问题:

  • 用户在搜索的时候,在不停的输入,如果每敲一个字我们就要调一次接口去查询,接口调用太频繁,会占内存给卡住。
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完面试官问你的优势在哪成后,计算窗口大小。防止重复渲染。
  • 页面滚动处理事件

原理分析

防抖:在事件被触发 n 秒后再执行回调函数,如果在这 n 秒内又被面试官最讨厌的6句话触发,则重新计时延指针迟时间

函数防抖原理:通过维护一个定时器,其延迟计时以最后一次触发为计时起点,到达延迟时间后才会触发函数组去重方法数执行。

防抖的实现方式分两种 “立即执行”“非立即执行”指针说漫区别在于第一次触发时,是否立即执行回调函数。

“立即执行防抖” 指事件触发后,回调函数会立即执行,之后elementui要想触发执行回调函数,需等待 n 秒延迟

”非立即执行防抖“ 指事件触发后,回调函数不会立即执行,会在延迟时间 n 秒后执行,如果 n 秒内被调用多次,则重新计时延迟时间

理解:

  • 相当于英雄数组去重大招,施法后要等技能冷却才能再次指针施法(立即执行)。
  • 法师发技能的时候要读条,技能读条没指针万用表怎么读数完再指针数组按技能就会重新读条(非立即执行)。

手写防抖

那么理解了什么是防抖,我们可以手写一个防抖,这不仅在面试中经常出数组和链表的区别现,工作中也会遇到。

非立即执行
<body>
  <button id="debounce">点击</button>
  <script>
    window.onload=function(){
      var mydebounce = document.getElementById("debounce")
      mydebounce.addEventListener("click",debounce(sayDebounce,1000))
     }
    //防抖函数
    function debounce(fn,time) {
      let timer = null
      return function () {
        let context = this
        if(timer) clearTimeout(timer) //清除前一个定时器
        timer = setTimeout(()=>{ //在时间间隙内再次点击不会执行fn函数
          fn.apply(context,arguments)
         },time || 500)
       }
     }
    //要防抖的事件处理
    function sayDebounce() {
      console.log("处理防抖的事件写在这里,比如发送请求");
     }
  </script>
</body>

特别说明:apply 是为了改变某个函数组公式数运行时的 context 即上下文而存在的,说人话就是改变this指针的指向,函数.apply(第一个参数就是你想吧this指针指向哪,第二个参数就是你向里面传的参数(arguments));

apply()方法接收两个参数,一个是函数运行的作用域(this),另一个是参数数组

call()方法第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。

在js中,所有的函数再被调用的时候都会默认传入两个参数,一个是this,还有一个是argu接口和抽象类的区别ments。在默认情况下this都是指当前的调用函数的对象。但是有时候我们需要改变this的指向,也就是说使函数可以被其他对象来调用,那么我们应接口是什么该怎样做呢?这时候我们就可以使用call和apply方法了;

但是问题来了,我不想点击了按钮要等一秒它才发起请求,It is too slow!能不能点击立即执行,再次点击才需要等待技能冷却?Of course!

立即执行
function debounce(fn,time) {
      let timer = null
      return function () {
        let context = this
        let args = arguments
        if(timer) clearTimeout(timer) //清除前一个定时器
        let callNow = !timer
        timer = setTimeout(()=>{ 
          timer = null
         },time || 500)
        if (callNow) fn.apply(context,args)
       }
     }

这个时候产数组词品经理又提了一个新需求:能不element是什么意思能这个按钮立即执行,那个按钮非立即执行?

”呵……我早就猜到你会提出这种无理的需求!看剑!“,

可以实现吗?”可以elements中文翻译,得加钱“。那我加个 immediate参数判断是否立即执行呗。

组合版本
<body>
    <button id="debounce">点击</button>
    <script>
      window.onload=function(){
      var mydebounce = document.getElementById("debounce")
      mydebounce.addEventListener("click",debounce(sayDebounce,1000,false))
     }
    //防抖函数
    function debounce(fn,time,immediate) {
      let timer = null
      return function () {
        let context = this
        let args = arguments
        if(timer) clearTimeout(timer) //清除前一个定时器
        if (immediate) { //为true立即执行
          let callNow = !timer
          timer = setTimeout(()=>{ 
            timer = null
           },time || 500)
          if (callNow) fn.apply(context,args)
         }
        else { //非立即执行
          timer = setTimeout(function(){
            fn.apply(context, args)
           }, time || 500);
         }
       }
     }
    //要防抖的事件处理
    function sayDebounce() {
      console.log("处理防抖的事件写在这里,比如发送请求");
     }
    </script>
  </body>

产品经理:”可不可以…….“, ”你走啊“

”能不能取消debounce函数,比如在登录时候的面试官的面试技巧有哪些重新请求短信验证码,错一次要等好久“

取消debounce(终极版)
<body>
    <button id="debounce">点击</button>
    <button id="dd">取消</button>
    <script>
      var mydebounce = document.getElementById("debounce")
      var Mydebounce = document.getElementById("dd")
      var set = debounce(sayDebounce,5000,true)
      mydebounce.addEventListener("click",set)
      Mydebounce.addEventListener("click",function () { 
        set.cancel() 
       } )
    
    //防抖函数
    function debounce(fn,time,immediate) {
      let timer = null
      let debounced = function () {
        let context = this
        let args = arguments
        if(timer) clearTimeout(timer) //清除前一个定时器
        if (immediate) { //为true立即执行
          let callNow = !timer
          timer = setTimeout(()=>{ 
            timer = null
           },time || 500)
          if (callNow) fn.apply(context,args)
         }
        else { //非立即执行
          timer = setTimeout(function(){
            fn.apply(context, args)
           }, time || 500);
         }
       }
      debounced.cancel = function() { //取消防抖
        clearTimeout(timer);
        timer = null;
       };
      return debounced
     }
    //要防抖的事件处理
    function sayDebounce() {
      console.log("处理防抖的事件写在这里,比如发送请求");
     }
    </script>
  </body>

面试官:你能手写一个防抖看看吗?

”看我不秀死你“