再学JS--事件防抖

作者: Territory_Cheng | 来源:发表于2020-07-16 18:04 被阅读0次

    在前端开发中会遇到一些频繁的事件触发,例如:

    1. window的resize、scroll
    2. mousedown、mousemove
    3. keyup、keydown

    频繁的触发会造成卡顿现象,为了解决这个问题,一般有两种解决方案:

    1. debounce防抖
    2. throttle节流

    防抖

    防抖的原理是:你尽管触发事件,但是我一定在事件触发n秒后执行,如果一个事件触发n秒内又触发了这个事件,那我就以新的事件的时间为准,n秒后执行,总之就是要等你触发事件n秒内不再触发事件。

    <html>
    <head>
        <meta charset="utf-8">
    
        <style>
            #container {
                width: 100%;
                height: 200px;
                line-height: 200px;
                text-align: center;
                color: #000;
                background-color: #ddd;
            }
        </style>
    </head>
    
    <body>
        <div id="container"></div>
    </body>
    
    <script>
        var count = 1;
        var container = document.getElementById('container')
    
        function getUserAction() {
            container.innerHTML = count++
        }
    
        container.onmousemove = getUserAction
    </script>
    
    </html>
    

    第一版

    function debounce(func, wait) {
        var timeout
        return function() {
            clearTimeout(timeout)
            timeout = setTimeout(func, wait)
        }
    }
    

    this

    getUserAction函数中,在不使用debounce时,this指向的是container的dom元素,在使用debounce时,this指向的是window,修改下代码修正this指向

    function debounce(func, wait) {
        var timeout
        return function() {
            var context = this
            clearTimeout(timeout)
            timeout = setTimeout(function() {
                func.apply(context)
            }, wait)
        }
    }
    

    event对象

    JavaScript在事件处理函数中会提供事件对象event,但在使用debounce时,event对象为undefined,修正下event对象问题

    function debounce(func, wait) {
        var timeout
        return function() {
            var context = this
            var args = arguments
    
            clearTimeout(timeout)
            timeout = setTimeout(function() {
                func.apply(context, args)
            }, wait)
        }
    }
    

    返回值

    getUserAction函数可能存在返回值,所以我们要返回函数执行的结果

    function debounce(func, wait) {
        var timeout, reslut
        return function() {
            var context = this
            var args = arguments
    
            clearTimeout(timeout)
            timeout = setTimeout(function() {
                reslut = func.apply(context, args)
            }, wait)
            
            return reslut
        }
    }
    

    立即执行

    立即执行需求是,我不想非要等到事件停止触发后才执行,我希望能立即执行函数,然后等到停止触发n秒后,才可以重新执行

    function debounce(func, wait, immediate) {
        var timeout, reslut
        
        return function() {
            var context = this
            var args = arguments
    
            if(timeout) clearTimeout(timeout)
    
            if(immediate) {
                // 如果已经执行过,不再执行
                var callNow = !timeout
                timeout = setTimeout(function() {
                    timeout = null
                }, wait)
                if(callNow) reslut = func.apply(context, args)
            } else {
                timeout = setTimeout(function() {
                    reslut = func.apply(context, args)
                }, wait)
            }
    
            return reslut
        }
    }
    

    取消

    可以支持取消debounce函数,比如说我debounce的时间为10秒,immediate为true,这样的话,我只有等10秒之后才能重新触发事件,现在我希望能主动取消debounce,可以再次触发函数

    function debounce(func, wait, immediate) {
        var timeout, reslut
        var debounced = function() {
            var context = this
            var args = arguments
    
            if(timeout) clearTimeout(timeout)
    
            if(immediate) {
                // 如果已经执行过,不再执行
                var callNow = !timeout
                timeout = setTimeout(function() {
                    timeout = null
                }, wait)
                if(callNow) reslut = func.apply(context, args)
            } else {
                timeout = setTimeout(function() {
                    reslut = func.apply(context, args)
                }, wait)
            }
    
            return reslut
        }
    
        debounced.cancel = function() {
            clearTimeout(timeout)
            timeout = null
        }
    
        return debounced
    }
    

    完整示例代码

    <html>
    <head>
        <meta charset="utf-8">
    
        <style>
            #container {
                width: 100%;
                height: 200px;
                line-height: 200px;
                text-align: center;
                color: #000;
                background-color: #ddd;
            }
        </style>
    </head>
    
    <body>
        <div id="container"></div>
        <button id="cancel">取消</button>
    </body>
    
    <script>
        var count = 1;
        var container = document.getElementById('container')
        var cancel = document.getElementById('cancel')
    
        function getUserAction(e) {
            container.innerHTML = count++
            console.log(e)
        }
    
        var debounceFun = debounce(getUserAction, 10000, true)
    
        container.onmousemove = debounceFun
    
        cancel.onclick = function() {
            debounceFun.cancel()
        }
    
        function debounce(func, wait, immediate) {
            var timeout, reslut
            var debounced = function() {
                var context = this
                var args = arguments
                
                if(timeout) clearTimeout(timeout)
    
                if(immediate) {
                    // 如果已经执行过,不再执行
                    var callNow = !timeout
                    timeout = setTimeout(function() {
                        timeout = null
                    }, wait)
                    if(callNow) reslut = func.apply(context, args)
                } else {
                    timeout = setTimeout(function() {
                        reslut = func.apply(context, args)
                    }, wait)
                }
        
                return reslut
            }
    
            debounced.cancel = function() {
                clearTimeout(timeout)
                timeout = null
            }
    
            return debounced
        }
    
    </script>
    
    </html>
    

    相关文章

      网友评论

        本文标题:再学JS--事件防抖

        本文链接:https://www.haomeiwen.com/subject/pyrmhktx.html