原生js实现函数防抖和函数节流

206 阅读3分钟

函数防抖和节流都是针对余频繁的操作dom或请求而做的优化。限制频繁的触发回掉函数和请求。本文主要详细介绍如何用原生的js实现函数的防抖以及函数节流。

函数防抖

1、原理。

响应函数(回调函数)在一段时间后执行,如果在这段时间内再次触发响应函数则重新计时。

2、具体代码实现

//函数防抖
const debounce = (cb, wait, triggerNow = false) => {
    let timer = null;    
    let result = null; // 保存函数返回值    
    const debounced = function () {    
        const context = this; // 保存当前环境的this(上下文)        
        const args = arguments; // 保存事件对象        
        timer && clearTimeout(timer); // 在每次进来时重置timer保证cb不会一直执行
        if (triggerNow) { //立即执行
            let callNow = !timer;
            timer = setTimeout(() => {
                timer = null;
                result = cb.apply(context, args);
            }, wait);
            if (callNow) {
                result = cb.apply(context, args);
            }
        } else {
            // 改变cb函数中的this指向 cb.apply(this);
            timer = setTimeout(() => cb.apply(context, args), wait);
        }
        return result;
    }
	//取消函数防抖
    debounced.cancle = () => { 函数是特殊的对象可以在函数上定义属性
        clearTimeout(timer);
        timer = null; // 重置timer防止闭包导致内存泄漏
    }
    return debounced;
}

3、应用场景

1、scroll事件、mousemove事件、浏览器resize事件

2、表单验证

3、搜索框输入查询

4、按钮提交事件

函数节流

1、原理

持续的触发响应事件,每隔一段时间只执行一次响应事件。缩减响应函数的执行频率

2、具体代码实现

1、利用时间戳实现 时间戳实现的函数节流,第一次会立即执行,但最后一次不会执行

const throttle1 = (cb, wait) => {
    let oldTime = 0; // 注意oldTime不能定义在返回函数的里面。利用闭包保存上一次oldTime的值
    return function() {
        const context = this;
        const args = arguments;
        let nowTime = new Date().getTime(); // 获取当前时间戳
        if((nowTime - oldTime) > wait) {
            cb.apply(context, arguments);
            oldTime = nowTime; 更新oldTime的值
        }
    }
}

2、借助定时器实现 利用定时器实现的函数节流:第一次不会执行,最后一次会执行

const thorttle2 = (cb, wait) => {
    let timer;

    return function() {
        const context = this;
        const args = arguments;
        if(!timer) {
            timer = setTimeout(() => {
                timer = null;
                cb.apply(context, args);
        }, wait);
    }
    }
}

3、结合时间戳和定时器实现,第一次执行,最后一次也执行的效果

const throttle3 = (cb, wait) => {
    let timer;
    let oldTime = 0;
    return function () {
        const context = this;
        const args = arguments;
        let nowTime = new Date().getTime();

        if (nowTime - oldTime > wait) {
            if (timer) {  // 清除定时器和重置timer
                clearTimeout(timer);
                timer = null;
            }
            cb.apply(context, args);
            oldTime = nowTime;
        }

        if (!timer) {
            timer = setTimeout(() => {
                oldTime = new Date().getTime(); // 重置oldTime
                timer = null;
                cb.apply(context, args);
            }, wait);
        }
    }

}

3、应用场景

1、监听scroll事件

2、dom元素拖拽

3、计算鼠标移动的距离

总结

1、函数防抖和函数节流都是优化高频率执行响应函数的方式。优化程序性能节省计算机资源。但是两者又有细微的差别。函数防抖:在一段时间之后执行响应函数,如果在这段时间内再次触发则重新计时。所以响应函数可能只执行一次。函数节流:响应函数在在设定的时间后执行,只要等待的时间大于设定的时间,响应函数就会继续执行。

2、函数防抖:根据triggerNow的值决定首次是否执行响应函数。

3、函数节流:时间戳实现的函数节流首次执行响应函数,最后不执行响应函数;而定时器实现的函数节流则是首次不执行响应函数,最后一次执行响应函数。使用时间戳和定时器结合实现的函数节流则是首次执行响应函数而且最后一次也执行响应函数。