js高級進階之函數防抖、截流

在前端開發實現相關功能時,由於js中部分事件的設計存在一定的問題,對完成業務帶來很大的困難,比如js的scrooll ,mouseover ,resize等事件瀏覽器是實時觸發實時相應的,那麼如果我們要對其進行監聽實現相關業務,那麼就會導致業務也被連續多次執行

看個例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #content{
            width: 400px;
            height: 400px;
            background-color: bisque;
            word-break: break-all;
        }
    </style>
</head>
<body>
    <div id = "content"></div>
</body>
<script>
    let e = document.getElementById("content");
    e.addEventListener("pointermove",function(){
        e.innerHTML += "c"
    })
</script>
</html>

此時如果鼠標放在div區域內不停移動,則監聽事件就會不停執行。我們當然不希望如此頻繁執行。就需要做節流處理。

防抖和節流概念

防抖:抖動停止後的時間超過設定的時間時執行一次函數。注意:這裏的抖動停止表示你停止了觸發這個函數,從這個時間點開始計算,當間隔時間等於你設定時間,纔會執行裏面的回調函數。如果你一直在觸發這個函數並且兩次觸發間隔小於設定時間,則一定不會到回調函數那一步。

節流:按照設定的時間固定執行一次函數。

區別:防抖着重於處理連續不間隔觸發,給定時間限制後只有大於這個時間限制的連續操作纔會執行,而節流是無論連續操作多少次(時間)只有在固定時間間隔採取執行。

使用場景
防抖:input驗證、resize
節流:scroll、mousemove

我們將上面的示例用節流方法進行改造

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #content{
            width: 400px;
            height: 400px;
            background-color: bisque;
            word-break: break-all;
        }
    </style>
</head>
<body>
    <div id = "content"></div>
</body>
<script>
    let e = document.getElementById("content");
    let fn = function(){
        e.innerHTML += "c"
    }
   
    function throttle(fn,delay=100){
        let last = 0;
        return function(){
            let curr = +new Date();
            if(curr - last > delay){
                fn.apply(this,arguments);
                last = curr;
            }
        }
    }
    e.addEventListener("pointermove",throttle(fn,500));

</script>
</html>

防抖改造:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #content{
            width: 400px;
            height: 400px;
            background-color: bisque;
            word-break: break-all;
        }
    </style>
</head>
<body>
    <div id = "content"></div>
</body>
<script>
    let e = document.getElementById("content");
    let fn = function(){
        e.innerHTML += "c"
    }

    //防抖
    function debounce(fn, delay, atBegin = true) {
        let timer = null, last = 0,during;
        return function () {
            let self = this, args = arguments;
            var exec = function () {
                fn.apply(self, args);
            }
            if (atBegin && !timer) {
                exec();
                atBegin = false;
            } else {
                during = Date.now() - last;
                if (during > delay) {
                    exec();
                } else {
                    if (timer) clearTimeout(timer);
                    timer = setTimeout(function () {
                        exec();
                    }, delay);
                }
            }
            last = Date.now();
        }
    }
    e.addEventListener("pointermove",debounce(fn,500));
</script>
</html>

防抖函數時間戳經典實現

function debounce(fn, delay, atBegin = true) {
        let timer = null, last = 0,during;
        return function () {
            let self = this, args = arguments;
            var exec = function () {
                fn.apply(self, args);
            }
            if (atBegin && !timer) {
                exec();
                atBegin = false;
            } else {
                during = Date.now() - last;
                if (during > delay) {
                    exec();
                } else {
                    if (timer) clearTimeout(timer);
                    timer = setTimeout(function () {
                        exec();
                    }, delay);
                }
            }
            last = Date.now();
        }
    }

節流函數時間戳經典實現

function throttle(fn,delay=100){
        let last = 0;
        return function(){
            let curr = +new Date();
            if(curr - last > delay){
                fn.apply(this,arguments);
                last = curr;
            }
        }
    }

本篇博文參考了http://caibaojian.com/throttle-debounce.html
感謝作者的分享,對作者表示敬意!

發佈了77 篇原創文章 · 獲贊 8 · 訪問量 6871
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章