JS实现防抖和节流

前言:

    防抖和节流在js中有很多应用的场景,比如监听滚动条事件,输入字符搜索次数的优化等等。不能只知其然而不知其所以然,所以有必要了解下实现的原理。

区别:

    防抖是在一段时间内不能执行某种操作。比如在搜索框这个场景,只有在500ms后没有输入新的字符,才会去调用接口进行搜索。

    节流则是有规律的执行某种操作。比如监听滚动条事件这个场景,在一直滚动时,每隔300ms会执行一次滚动条事件的回调。

防抖:

/**
 * 函数防抖
 * @param func 目标函数
 * @param delay 延迟时间
 * @param immediate 是否立即执行,是指在触发后是否先执行一遍目标函数
 */
function debounce (func, delay, immediate) {
	let timer = null; // 通过闭包来保存timer的值
	let _debounce = function () {
		const context = this;
		const args = arguments;
		if (timer) {
			clearTimeout(timer);
		}
		if (immediate) {
			let callNow = !timer; // 如果timer为null说明是第一次执行
			timer = setTimeout(() => {
				timer = null;
			}, delay);
			if (callNow) {
				func.apply(context, args);
			}
		} else {
			timer = setTimeout(() => {
				func.apply(context, args);
			}, delay);
		}
	}
	_debounce.cancel = function () {
		clearTimeout(timer);
		timer = null;
	}
	return _debounce;
}

  

节流:

/**
 * 函数节流
 * @param func 目标函数
 * @param delay 延迟时间
 * @param options options.leading:是否在刚触发后立即执行目标函数
 *                options.trailing:是否在停止触发后还执行一次目标函数
 */
function throttle (func, delay, options) {
	let timer;
	let previous = 0; // 上一次执行的时间点
	options = options || {};
	
	const _throttle = function () {
		const context = this;
		const args = arguments;
        const now = +new Date();
        // 如果leading为false,则设置上一次执行的时间点为当前,自然也就不会立马执行目标函数了
		if (!previous && options.leading === false) {
			previous = now;
        }
        // 计算距离上次执行的时间点还剩多少时间
        const remaining = delay - (now - previous);
        // 如果剩余时间小于等于0,说明从上次执行到当前已经超过了设定的delay间隔
        // 如果剩余时间大于设定的delay,说明当前系统时间被修改过
		if (remaining <= 0 || remaining > delay) {
			if (timer) {
				clearTimeout(timer);
				timer = null;
			}
			func.apply(context, args);
			previous = now;
		} else if (!timer && options.trailing === true) {
			timer = setTimeout(() => {
                // 如果leading为false代表下次触发后不需要立马执行目标函数,所以设置为0,在17行才会顺利进入判断
				previous = options.leading === false ? 0 : +new Date();
				func.apply(context, args);
				timer = null;
			}, remaining); // 此处设定为计算距离上次执行的时间点剩余的时间,使用setTimeout保证了即使后续不触发也能再执行一次目标函数
		}
	}
	
	_throttle.cancel = function () {
		clearTimeout(timer);
		timer = null;
		previous = 0;
	}
}

  

 

上一篇:django快速做一个博客项目(3)


下一篇:Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法