zl程序教程

您现在的位置是:首页 >  后端

当前栏目

浅谈JS函数防抖及应用场景

JS应用 函数 场景 浅谈 防抖
2023-09-11 14:19:06 时间

【前言】

在工作中,我们可能碰到这样的问题:

  • 用户在搜索的时候,在不停敲字,如果每敲一个字我们就要调一次接口,接口调用太频繁,给卡住了。
  • 用户在阅读文章的时候,我们需要监听用户滚动到了哪个标题,但是每滚动一下就监听,那样会太过频繁从而占内存,如果再加上其他的业务代码,就卡住了。

所以,这时候,我们就要用到 防抖与节流 了。

那么,讲到 防抖与节流,我们可以顺带探秘下 重绘与回流

说起 重绘与回流,我们就顺带把 浏览器输入 URL 后发生的事情 也关注一下,从而引出 DNSTCP 等知识点,最终串起来构成本文的轮廓,方便 jsliang 和小伙伴们对这块知识的整理与记忆。

【主体】

本节主要介绍函数防抖debounce

下面我们有段防抖小案例代码。

如果小伙伴们手头有电脑,并感兴趣想先自己思考下什么是防抖。可以将代码复制到浏览器,尝试点击按钮,并关注下控制台,看看 Console 是如何打印的。

如果小伙伴们手头没有电脑,那么咱一起先瞅瞅代码实现,再看看下面 GIF 演示。(这样效果没有自己敲的直白有效)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>防抖</title>
</head>
<body>
  <button id="debounce">点我防抖!</button>

  <script>
    window.onload = function() {
      // 1、获取这个按钮,并绑定事件
      var myDebounce = document.getElementById("debounce");
      myDebounce.addEventListener("click", debounce(sayDebounce));
    }

    // 2、防抖功能函数,接受传参
    function debounce(fn) {
      // 4、创建一个标记用来存放定时器的返回值
      let timeout = null;
      return function() {
        // 5、每次当用户点击/输入的时候,把前一个定时器清除
        clearTimeout(timeout);
        // 6、然后创建一个新的 setTimeout,
        // 这样就能保证点击按钮后的 interval 间隔内
        // 如果用户还点击了的话,就不会执行 fn 函数
        timeout = setTimeout(() => {
          fn.call(this, arguments);
        }, 1000);
      };
    }

    // 3、需要进行防抖的事件处理
    function sayDebounce() {
      // ... 有些需要防抖的工作,在这里执行
      console.log("防抖成功!");
    }

  </script>
</body>
</html>

很好,相信小伙伴们已经看完了代码,下面我们看看它的演示:

这时候,我们可以抛出防抖的概念了:

  • 防抖任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。

结合上面的代码,我们可以了解到,在触发点击事件后,如果用户再次点击了,我们会清空之前的定时器,重新生成一个定时器。意思就是:这件事儿需要等待,如果你反复催促,我就重新计时!

空讲无益,show you 场景:

  • 有个输入框,输入之后会调用接口,获取联想词。但是,因为频繁调用接口不太好,所以我们在代码中使用防抖功能,只有在用户输入完毕的一段时间后,才会调用接口,出现联想词。

小伙伴们可以尝试看着上面的案例,先自己实现一遍这个场景的解决,如果感觉不行,那就看:《防抖和节流的应用场景和实现》

知识点补充:何为 arguments
首先,后端转前端的同学,可以将 arguments 理解为能实现重载函数功能的工具。
然后,我们举个例子:在 function test() 这个方法中,由于我们不确定变量有多少,比如 test("jsliang", 24),又或者 test("LiangJunrong", "jsliang", "24"),这时候只需要在函数 test 中用 arguments 接收就行了。
最后,在 function test() { let arr1 = argument[0] } 中,arr1 就可以获取到传进来的第一个变量。
所以fn.call(this, arguments) 其实是将不确定变量替换到函数中了。

参考资料 1:《闲聊 JS 中的 apply 和 call》
参考资料 2:《js 中 arguments 的用法》

 
案例2:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>demo</title>
</head>
<body>
    <input type="text" name="search">

    <script type="text/javascript">
        var searchInput = document.querySelector('input[name="search"]');
        /*绑定事件*/
        searchInput.addEventListener('keyup',debounce(getInputValue),false);
        /* 防抖函数 */
        function debounce(fn){
            var timer = null;
            return function(){
                if(timer){
                    clearTimeout(timer)
                }
                timer = setTimeout(()=>{
                    fn.call(this,arguments)
                },500)
            }
        }
        /* 调用获取输入值 */
        function getInputValue(){
            console.dir(this.value)
        }
    </script>
</body>
</html>

 

 

 

 

.