防抖

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

解决两个问题:

  1. this的指向
  2. event对象
var count = 1;
var container = document.getElementById('container');
function getUserAction(e) {
    console.log(e)
    container.innerHTML = count++;
    //console.log(this) //  此时的this指向的window,本来应该是<div id="container"></div>
};
// container.onmousemove = getUserAction;
container.onmousemove = debounce(getUserAction,1000)


function debounce(func,wait){
    var timeout
    return function(){
        // 修复this指向
        var that = this
        // 修复event对象
        var args = arguments
        //先清除掉之前的定时器
        clearTimeout(timeout)
        //设置定时器,wait秒之后执行
        timeout = setTimeout(function(){
            func.apply(that,args)
        },wait)
    } 
}

需求1-立刻执行

不希望事件停止触发之后才执行,而是希望立刻执行函数,然后等到停止触发n秒之后,才可以重新执行。简单,只需要加一个判断,是不是立刻执行。

var count = 1;
var container = document.getElementById('container');
function getUserAction(e) {
    console.log(e)
    container.innerHTML = count++;
    //console.log(this) //  此时的this指向的window,本来应该是<div id="container"></div>
};
// container.onmousemove = getUserAction;
container.onmousemove = debounce(getUserAction,1000,true)
function debounce(func,wait,immediate){
    var timeout
    return function(){
        // 修复this指向
        var that = this
        // 修复event对象
        var args = arguments
        if(timeout) clearTimeout(timeout)
        if(immediate){ // ->判断是不是立刻执行的
            // 如果已经执行过,不再执行
            var callNow = !timeout
            timeout = setTimeout(function(){
                timeout = null
            },wait)
            if(callNow) func.apply(that,args)
        }else{
            //设置定时器,wait秒之后执行
        timeout = setTimeout(function(){
            func.apply(that,args)
        },wait)

        }
       // + return result // 111
    } 
}
/**
如果getUserAction有返回值的话,当immediate为false的时候,因为使用了定时器又不是立刻执行,我们需要将func.apply(that,args)的返回值赋给变量,最后return的时候,值是undefined,所以我们只在immediate为true的时候返回函数的结果
           - var timeout
           + var timeout,result
           - if(callNow) func.apply(that,args)
           + if(callNow)  result = func.apply(that,args)
           + return result // 111
*/

需求2-取消防抖

function debounce(func, wait, immediate) {

    var timeout, result;

    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) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
        return result;
    };

    debounced.cancel = function() {
        clearTimeout(timeout);
        timeout = null;
    };

    return debounced;
}