小菊花課堂之JS的防抖與節流

前言

陸游有一首《冬夜讀書示子聿》——「古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。」,其中的意思想必你們都能明白,在學習或工做中,不斷的印證着這首詩的內涵。因此,又有了此篇小菊花文章。javascript

詳解

在前端開發中,咱們常常會碰到一些會持續觸發的時間,好比 輸入框校驗、resize、scroll、mousemove 等操做時,若是事件觸發的頻率無限制,會家中瀏覽器的負擔,致使用戶體驗很是糟糕。
咱們能夠先看看持續觸發過程當中頻繁執行函數是怎樣的狀況css

<div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div>
<script>
    var num = 1;
    var content = document.getElementById('content');

    function count() {
        content.innerHTML = num++;
    };

    content.onmousemove = count;
</script>

圖片描述
在上面代碼中,div 元素綁定了 mousemove 事件,當鼠標在 div(灰色)區域中移動的時候會持續地去觸發該事件致使頻繁執行函數。html

再看一個例子前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>沒有防抖</title>
    <style type="text/css"></style>
    <script type="text/javascript">
        window.onload = function () {
            //模擬ajax請求
            function ajax(content) {
                console.log('ajax request ' + content)
            }
            let inputNormal = document.getElementById('normal');

            inputNormal.addEventListener('keyup', function (e) {
                ajax(e.target.value)
            })
        }
    </script>
</head>
<body>
    <div>
        1.沒有防抖的input:
        <input type="text" name="normal" id="normal">
    </div>
</body>
</html>

圖片描述

在上面代碼中,會監聽鍵盤輸入事件,只要按下鍵盤,就會觸發此次模擬的ajax請求,不只浪費了資源,並且在實際應用中,用戶也是須要輸入完整字符後,才請求。java

防抖(debounce)

簡單來講就是防止抖動,指觸發事件在 n 秒內函數只能執行一次,若是在 n 秒內又觸發了事件,則會從新計算函數執行時間。
咱們將上面的代碼加入防抖優化一下:ajax

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>加入防抖</title>
    <style type="text/css"></style>
    <script type="text/javascript">
        window.onload = function () {
            //模擬ajax請求
            function ajax(content) {
                console.log('ajax request ' + content)
            }
            function debounce(fun, delay) {
                return function (args) {
                    //獲取函數的做用域和變量
                    let that = this
                    let _args = args
                    //每次事件被觸發,都會清除當前的timeer,而後重寫設置超時調用
                    clearTimeout(fun.id)
                    fun.id = setTimeout(function () {
                        fun.call(that, _args)
                    }, delay)
                }
            }
            let inputDebounce = document.getElementById('debounce')
            let debounceAjax = debounce(ajax, 500)
            inputDebounce.addEventListener('keyup', function (e) {
                debounceAjax(e.target.value)
            })
        }
    </script>
</head>
<body>
    <div>
        2.加入防抖後的輸入:
        <input type="text" name="debounce" id="debounce">
    </div>
</body>
</html>

圖片描述

上面代碼加入防抖後,當持續在輸入框裏輸入時,並不會發送請求,只有當在指定時間間隔內沒有再輸入時,纔會發送請求。若是先中止輸入,可是在指定間隔內又輸入,會從新觸發計時。segmentfault

節流(throttle)

規定一個單位時間,在這個單位時間內,只能有一次觸發事件的回調函數執行,若是在同一個單位時間內某事件被觸發屢次,只有一次能生效。
咱們一樣在上面的需求上進行修改,加入節流函數。瀏覽器

//模擬ajax請求
function ajax(content) {
    console.log('ajax request ' + content)
}

function throttle(fun, delay) {
    let last, deferTimer
    return function (args) {
        let that = this;
        let _args = arguments;

        let now = +new Date();
        if (last && now < last + delay) {
            clearTimeout(deferTimer);
            deferTimer = setTimeout(function () {
                last = now;
                fun.apply(that, _args);
            }, delay)
        } else {
            last = now;
            fun.apply(that, _args);
        }
    }
}
let throttleAjax = throttle(ajax, 1000)
let inputThrottle = document.getElementById('throttle')
inputThrottle.addEventListener('keyup', function (e) {
    throttleAjax(e.target.value)
})

圖片描述

從上面代碼能夠看出,規定每一秒執行一次ajax請求,效果圖也能比較清晰的反應出來。app

小結

區別

函數防抖是某一段時間內只執行一次;而函數節流是間隔時間執行,無論事件觸發有多頻繁,都會保證在規定時間內必定會執行一次真正的事件處理函數。函數

在其餘同窗的文章中看到這樣的解釋:
防抖 — 若是有人進電梯(觸發事件),那電梯將在10秒鐘後出發(執行事件監聽器),這時若是又有人進電梯了(在10秒內再次觸發該事件),咱們又得等10秒再出發(從新計時)。

節流 — 咱們知道目前的一種說法是當 1 秒內連續播放 24 張以上的圖片時,在人眼的視覺中就會造成一個連貫的動畫,因此在電影的播放(之前是,如今不知道)中基本是以每秒 24 張的速度播放的,爲何不 100 張或更可能是由於 24 張就能夠知足人類視覺需求的時候,100 張就會顯得很浪費資源。

這大概能夠較爲清晰的講出這二者的區別吧。

原理

防抖是維護一個計時器,規定在delay時間後觸發函數,可是在delay時間內再次觸發的話,都會清除當前的 timer 而後從新設置超時調用,即從新計時。這樣一來,只有最後一次操做能被觸發。

節流是經過判斷是否到達必定時間來觸發函數,若沒到規定時間則使用計時器延後,而下一次事件則會從新設定計時器。

文章來源
1.詳談js防抖和節流
2.輕鬆理解JS函數節流和函數防抖
3.函數防抖和節流

好啦,今天的小菊花課堂之JS的防抖與節流的內容就告一段落啦,感各位能耐心看到這裏。
see u ~ again

相關文章
相關標籤/搜索