函数防抖和节流

  • 概述

debounce(防抖)和throttle(节流)都是限制函数执行频次,可用于性能优化。throttle强制一个函数随时间调用的最大次数,如“每100毫秒最多执行一次函数”;debounce(强制一个函数在经过一段时间之后才会被调用,如“仅在100毫秒之后才会执行该函数”,如果按照100毫秒之后执行函数的规则来限制,那么事件会在触发100毫秒后再执行,如果100毫秒内又触发了,则重新计时。

  • 应用场景

​ 如果将滚动处理函数附加到DOM元素上,则尽可能会看到100多个事件被触发,如果事件做了大量繁杂的工作,会非常影响性能,出现延迟、假死、卡顿等现象,导致用户体验极差。所以一般用于window对象的scrollresize事件,拖拽时的mousemove事件,文字输入或自动完成的keyup事件。

  • 代码演示
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>防抖和节流效果演示</title>
    <style type="text/css">
        * {
            box-sizing: border-box;
        }
        body {
            background: #eee;
        }

        .area {
            width: 300px;
            height: 200px;
            margin: 20px auto;
            background: white;
            position: relative;
        }

        .inside {
            height: 200px;
            position: relative;
            overflow: auto;
        }

        .content {
            height: 5000px;
        }

        .thing {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            text-align: center;
            background: #f06d06;
            color: white;
            padding: 10px;
        }

        .count {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
    </style>
</head>
<body>
<div class="area area-1">
    <div class="inside inside-1">
        <div class="content content-1"></div>
        <div class="thing thing-1">没有处理</div>
    </div>
    <div class="count count-1">0</div>
</div>
<div class="area area-2">
    <div class="inside inside-2">
        <div class="content content-2"></div>
        <div class="thing thing-2">节流</div>
    </div>
    <div class="count count-2">0</div>
</div>
<div class="area area-3">
    <div class="inside inside-3">
        <div class="content content-3"></div>
        <div class="thing thing-3">防抖</div>
    </div>
    <div class="count count-3">0</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script src="https://cdn.bootcss.com/lodash.js/4.17.12-pre/lodash.js"></script>
<script type="text/javascript">
    var inside1 = $(".inside-1");
    var thing1 = $(".thing-1");
    var count1 = $(".count-1");
    inside1.on("scroll",function(){
        thing1.css('top',inside1[0].scrollTop);
        count1.html(parseInt(count1.html())+1);
    });

    var inside2 = $(".inside-2");
    var thing2 = $(".thing-2");
    var count2 = $(".count-2");
    inside2.on("scroll",_.throttle(function(){
        thing2.css('top',inside2[0].scrollTop);
        count2.html(parseInt(count2.html())+1);
    },150));

    var inside3 = $(".inside-3");
    var thing3 = $(".thing-3");
    var count3 = $(".count-3");
    inside3.on("scroll",_.debounce(function(){
        thing3.css('top',inside3[0].scrollTop);
        count3.html(parseInt(count3.html())+1);
    },100));
</script>
</body>
</html>

以上代码中使用了lodashthrottledebounce操作,代码执行后,在浏览器中执行后,即可直观看到调用效果差异

  • 自定义

下面我们开始动手自己实现简单的防抖和节流函数

防抖-debounce

//防抖
function _debounce(fn,wait){
    var timer = null;
    return function(timer){
        clearTimeout(timer);
        timer = setTimeout(function(){
            fn();
        },wait)
    }
}
//_debounce(_log,500);
//如果一直执行滚动之类的操作,且保证能够执行很久,那么有可能函数一直不会执行,所以需进一步改进
function _debounce(fn,wait,time){
    var previus = null;
    var timer = null;
    return function(){
        var now = new Date();
        if(!previus){
            previus = now;
        }
        if(now - previus > time){
            clearTimeout(timer);
            fn();
            previus = now;
         } else {
            clearTimeout(timer);
            timer = setTimeout(function(){
               fn();
            },wait);
        }
    }
}
function _log() {
    console.log(1);
}
//_debounce(_log,500,2000);

节流-throttle

function _throttle(fn, time) {
    let _self = fn;
    let timer;
    let firstFlag = true;
    return function(){
        let args = arguments;
        let _this = this;
        if(firstFlag){
            _self.apply(_this,args);
            return firstFlag = false;
        }
        if(timer){
            return false;
        }
        timer = setTimeOut(function(){
            clearTimeOut(timer);
            timer = null;
            _self.appply(_this,args);
        },time || 500);
    }
}
function _log() {
    console.log(1);
}
//_throttle(_log,500);

你可能感兴趣的:(前端,js基础)