防抖的源码学习

179 阅读2分钟

防抖的原理:事件响应函数在一段事件后才执行,如果这段时间内再次调用,则重新计算执行事件,当预定的时间内没有再次调用该函数,则调用时间响应函数(意思就是时间触发之间的间隔必须大于设置时间)

应用场景

  • scroll事件滚动触发
  • 搜索框输入查询
  • 表单验证
  • 按钮提交事件
  • 浏览器窗口缩放、resize事件
debounce.js文件
/* 
@function
    debounce:鼠标在目标元素移动mousemove绑定的事件
    (频繁的事件触发还有window的resize,scroll;mousedown,mousemove;keydown,keyup
    getUserAction:改变数字的动作
@paras
    count:记住触发的次数
    timeout:每次mousemove都会产生的定时器
    result:考虑getUserAction有返回值,只有再immediate为true才有返回值
    immediate:立即执行功能(默认为false)
    callNow:是否立即执行的标志
*/


function debounce(func, wait, immediate) {
    var timeout;
    var result;

    var debounced = function () {
        var context = this; // this-> container
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        // 立即执行,不需要等到事件停止触发后才执行,希望立即执行,然后等到n秒后可以重新触发执行
        if (immediate) {
            // 已经执行过的不再执行
            var callNow = !timeout;

            //等待n秒后可以重新触发
            timeout = setTimeout(function () {
                timeout = null;
            }, wait);

            // 立即执行
            if (callNow) result = func.apply(context, args);
        }
        else {
            // 不会立即执行,设置定时操作
            timeout = setTimeout(function () { //这里使用箭头函数也可以实现this指向的改变
                console.log(this);// -> window
                func.apply(context, args);  // -> container  args传入鼠标事件对象MouseEvent
            }, wait);//等待n秒后,执行func(),同时改变this指向
        }
        return result;
    };
    debounced.cancel = function () {
        clearTimeout(timeout);
        timeout = null; //防止内存泄漏
    };
    return debounced;
}



var count = 1;
var container = document.getElementById('container'); //获取container元素
var btn = document.getElementById('btn');

// 改变数字的动作
function getUserAction(e) {
    // 可能做回调或者ajax请求(这样大量的无效的请求,对服务器是负担)
    container.innerHTML = count++;

    // event指向
    console.log(e);

    //改变执行函数内部的this
    console.log(this);// -> container
}


var setUserAction = debounce(getUserAction, 1000);
// this->container
container.onmousemove = setUserAction;
btn.onclick = function () { setUserAction.cancel(); console.log("ok"); }




//取消功能只能在immediate为false下才有意义
html文件
<!DOCTYPE html>
<html lang="zh-cmn-Hans">

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1">
    <title>debounce</title>
    <style>
        #container {
            width: 100%;
            height: 200px;
            line-height: 200px;
            text-align: center;
            color: #fff;
            background-color: #444;
            font-size: 30px;
        }

        button {
            display: block;
            top: 20px;
            left: 20px;
        }
    </style>
</head>

<body>
    <div id="container"></div>
    <button id="btn">取消</button>
    <script src="debounce.js"></script>
</body>

</html>