<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                防抖和節流嚴格算起來應該屬于性能優化的知識,但實際上遇到的頻率相當高,處理不當或者放任不管就容易引起瀏覽器卡死。所以還是很有必要早點掌握的。(信我,你看完肯定就懂了) ## 從滾動條監聽的例子說起 先說一個常見的功能,很多網站會提供這么一個按鈕:用于返回頂部。 ![](https://box.kancloud.cn/dc905a29edacdf8a12afe671243710f1_996x430.png) 這個按鈕只會在滾動到距離頂部一定位置之后才出現,那么我們現在抽象出這個功能需求-- **監聽瀏覽器滾動事件,返回當前滾條與頂部的距離** 這個需求很簡單,直接寫: ``` function showTop () { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;   console.log('滾動條位置:' + scrollTop); } window.onscroll = showTop ``` 但是! ![](https://box.kancloud.cn/22c3c169ee411975ec7e211c963e777c_294x291.png) 在運行的時候會發現存在一個問題:**這個函數的默認執行頻率,太!高!了!**。 高到什么程度呢?以chrome為例,我們可以點擊選中一個頁面的滾動條,然后點擊一次鍵盤的【向下方向鍵】,會發現函數執行了**8-9**次! ![](https://box.kancloud.cn/dcb0b3b91ee23190e17a78fa7b29f77b_991x679.png) 然而實際上我們并不需要如此高頻的反饋,畢竟瀏覽器的性能是有限的,不應該浪費在這里,所以接著討論如何優化這種場景。 ## 防抖(debounce) 基于上述場景,首先提出第一種思路:**在第一次觸發事件時,不立即執行函數,而是給出一個期限值比如200ms**,然后: - 如果在200ms內沒有再次觸發滾動事件,那么就執行函數 - 如果在200ms內再次觸發滾動事件,那么當前的計時取消,重新開始計時 **效果**:如果短時間內大量觸發同一事件,只會執行一次函數。 **實現**:既然前面都提到了計時,那實現的關鍵就在于`setTimeOut`這個函數,由于還需要一個變量來保存計時,考慮維護全局純凈,可以借助閉包來實現: ``` /* * fn [function] 需要防抖的函數 * delay [number] 毫秒,防抖期限值 */ function debounce(fn,delay){ let timer = null //借助閉包 return function() { if(timer){ clearTimeout(timer) //進入該分支語句,說明當前正在一個計時過程中,并且又觸發了相同事件。所以要取消當前的計時,重新開始計時 timer = setTimeOut(fn,delay) }else{ timer = setTimeOut(fn,delay) // 進入該分支說明當前并沒有在計時,那么就開始一個計時 } } } ``` 當然 上述代碼是為了貼合思路,方便理解(這么貼心不給個贊咩?),寫完會發現其實 time = setTimeOut(fn,delay)是一定會執行的,所以可以稍微簡化下: ``` /*****************************簡化后的分割線 ******************************/ function debounce(fn,delay){ let timer = null //借助閉包 return function() { if(timer){ clearTimeout(timer) } timer = setTimeout(fn,delay) // 簡化寫法 } } // 然后是舊代碼 function showTop () { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;   console.log('滾動條位置:' + scrollTop); } window.onscroll = debounce(showTop,1000) // 為了方便觀察效果我們取個大點的間斷值,實際使用根據需要來配置 ``` 此時會發現,必須在停止滾動1秒以后,才會打印出滾動條位置。 到這里,已經把防抖實現了,現在給出定義: 對于**短時間內連續觸發**的事件(上面的滾動事件),**防抖的含義就是讓某個時間期限(如上面的1000毫秒)內,事件處理函數只執行一次**。 ## 節流(throttle) 繼續思考,使用上面的防抖方案來處理問題的結果是: - 如果在限定時間段內,不斷觸發滾動事件(比如某個用戶閑著無聊,按住滾動不斷的拖來拖去),只要不停止觸發,理論上就永遠不會輸出當前距離頂部的距離。 **但是如果產品同學的期望處理方案是:即使用戶不斷拖動滾動條,也能在某個時間間隔之后給出反饋呢?**(此處暫且不論哪種方案更合適,既然產品爸爸說話了我們就先考慮怎么實現) ![](https://box.kancloud.cn/b22a74cfb68157cd5a3f3584b9e008b9_298x289.png) 其實很簡單:我們可以設計一種**類似控制閥門一樣定期開放的函數,也就是讓函數執行一次后,在某個時間段內暫時失效,過了這段時間后再重新激活**(類似于技能冷卻時間)。 **效果**:如果短時間內大量觸發同一事件,那么**在函數執行一次之后,該函數在指定的時間期限內不再工作**,直至過了這段時間才重新生效。 **實現**: 這里借助`setTimeout`來做一個簡單的實現,加上一個狀態位`valid`來表示當前函數是否處于工作狀態 ``` function throttle(fn,delay){ let valid = true return function() { if(!valid){ //休息時間 暫不接客 return false } // 工作時間,執行函數并且在間隔期內把狀態位設為無效 valid = false setTimeout(() => { fn() valid = true; }, delay) } } /* 請注意,節流函數并不止上面這種實現方案, 例如可以完全不借助setTimeout,可以把狀態位換成時間戳,然后利用時間戳差值是否大于指定間隔時間來做判定。 也可以直接將setTimeout的返回的標記當做判斷條件-判斷當前定時器是否存在,如果存在表示還在冷卻,并且在執行fn之后消除定時器表示激活,原理都一樣 */ // 以下照舊 function showTop () { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;   console.log('滾動條位置:' + scrollTop); } window.onscroll = throttle(showTop,1000) ``` 運行以上代碼的結果是: - 如果一直拖著滾動條進行滾動,那么會以1s的時間間隔,持續輸出當前位置和頂部的距離 ## 其他應用場景舉例 講完了這兩個技巧,下面介紹一下平時開發中常遇到的場景: 1. 搜索框input事件,例如要支持輸入實時搜索可以使用節流方案(間隔一段時間就必須查詢相關內容),或者實現輸入間隔大于某個值(如500ms),就當做用戶輸入完成,然后開始搜索,具體使用哪種方案要看業務需求。 2. 頁面resize事件,常見于需要做頁面適配的時候。需要根據最終呈現的頁面情況進行dom渲染(這種情形一般是使用防抖,因為只需要判斷最后一次的變化情況 ## 思考總結 上述內容基于防抖和節流的核心思路設計了簡單的實現算法,但是不代表實際的庫(例如undercore js)的源碼就直接是這樣的,最起碼的可以看出,在上述代碼實現中,因為`showTop`本身的很簡單,無需考慮作用域和參數傳遞,所以連`apply`都沒有用到,實際上肯定還要考慮傳遞`argument`以及上下文環境(畢竟apply需要用到this對象)。這里的相關知識在**本專欄**`《柯里化》`**和**`《this對象》`的文章里也有提到。本文依然堅持突出核心代碼,盡可能剝離無關功能點的思路行文因此不做贅述。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看