# 防抖和节流的作用和实现

# 防抖

在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

  1. search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
  2. window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
// 防抖:非立即执行版
function debounce1(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => {
            func.apply(context, args)
        }, wait);
    }
} 

// 防抖:立即执行版 
function debounce2(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        let callNow = !timeout;
        timeout = setTimeout(() => {
            timeout = null;
        }, wait)
        if (callNow) func.apply(context, args)
    }
}

// 防抖:双剑合璧版 
/**
 * 
 * @desc 函数防抖 
 * @param func 函数 
 * @param wait 延迟执行毫秒数
 * @param immediate 立即执行 true 表立即执行,false 表非立即执行 
 */
function debounce3(func, wait, immediate) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(() => {
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        } else {
            timeout = setTimeout(function() {
                func.apply(context, args)
            }, wait);
        }
    }
}

# 节流

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

  1. 鼠标不断点击触发,mousedown(单位时间内只触发一次)
  2. 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断页面频繁点击
// 节流:时间戳版 
function throttle(func, wait) {
    let previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
}

// 节流:定时器版 
function throttle(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                func.apply(context, args)
            }, wait)
        }
    }
}

// 节流:双剑合璧版 
/** 
 * @desc 函数节流 
 * @param func 函数 
 * @param wait 延迟执行毫秒数 
 * @param type 1 表时间戳版,2 表定时器版 
 */
function throttle(func, wait, type) {
    if (type === 1) {
        let previous = 0;
    } else if (type === 2) {
        let timeout;
    }
    return function() {
        let context = this;
        let args = arguments;
        if (type === 1) {
            let now = Date.now();
            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        } else if (type === 2) {
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }
    }
}