js 实现函数防抖(debounce)和函数节流(throttle)

一、函数防抖(debounce)

函数防抖:函数只有在空闲足够的时间时才执行,空闲时长不够就不执行。

应用场景:

  • 实时搜索(keyup、input)
  • 拖拽(mousemove)
/**
 * 函数防抖 debounce
 * @param {Object} func 要执行的函数
 * @param {Object} wait 延迟时间
 * @param {Object} immediate 是否立即执行
 */
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;
}

/**
 * 使用示例:
 */
var count = 1;
var container = document.getElementById('container');
function getUserAction(e) {
    container.innerHTML = count++;
};
var setUseAction = debounce(getUserAction, 10000, true);
container.onmousemove = setUseAction;
document.getElementById('button').addEventListener('click', function(){
    setUseAction.cancel();
})

二、函数节流(throttle)

函数节流:函数只有在大于等于执行周期时才执行,周期内不执行。

应用场景:

  • 窗口调整(resize)
  • 页面滚动(scroll)
  • 抢购疯狂点击(mousedown)
/**
 * 函数节流 throttle
 * @param {Object} func 要执行的函数
 * @param {Object} wait 等待时间
 * @param {Object} options 配置项,配置是否立即/延迟执行
 * {leading: false} 表示禁用第一次执行;{trailing: false} 表示禁用停止触发的回调(二选一)
 */
function throttle(func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        func.apply(context, args);
        if (!timeout) context = args = null;
    };

    var throttled = function() {
        var now = new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
        }
    };
	
	throttled.cancel = function() {
	    clearTimeout(timeout);
	    previous = 0;
	    timeout = null;
	}
	
    return throttled;
}

/**
 * 使用示例:
 */
var count = 1;
var container = document.getElementById('container');
function getUserAction(e) {
    container.innerHTML = count++;
};
// 有头有尾:第一次执行,停止后还会执行一次
container.onmousemove = throttle(getUserAction, 1000);
// 无头有尾:禁用第一次执行
container.onmousemove = throttle(getUserAction, 1000, {
    leading: false
});
// 由头无尾:禁用停止后的执行
container.onmousemove = throttle(getUserAction, 1000, {
    trailing: false
});

参考资料:
JavaScript专题之跟着 underscore 学防抖
JavaScript专题之跟着 underscore 学节流

你可能感兴趣的:(javascript,工具库)