淺談JS函數防抖及應用場景


【前言】

在工作中,我們可能碰到這樣的問題:

  • 用戶在搜索的時候,在不停敲字,如果每敲一個字我們就要調一次接口,接口調用太頻繁,給卡住了。
  • 用戶在閱讀文章的時候,我們需要監聽用戶滾動到了哪個標題,但是每滾動一下就監聽,那樣會太過頻繁從而占內存,如果再加上其他的業務代碼,就卡住了。

所以,這時候,我們就要用到 防抖與節流 了。

那么,講到 防抖與節流,我們可以順帶探秘下 重繪與回流

說起 重繪與回流,我們就順帶把 瀏覽器輸入 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>

 

 

 

 

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM