防抖、节流函数学习总结

概念

1、防抖
一定时间内仅执行一次,如果未到截止时间再次触发,则重新计算(也就是说如果一直不停的触发,那么这个函数一直不会执行,直到停止触发并且到了时间才会被执行)
应用场景:手机上滑加载数据

2、节流
一定时间内仅执行一次,如果未到截止时间再次触发,则触发不会生效(也就是说如果一直不停的触发,也只会每固定时间间隔执行一次,在时间范围内无法触发事件)
应用场景:搜索框输入即时搜索

说明
防抖和节流的目的都是为了控制函数调用频率,节省资源
但是侧重点不同,防抖是“您说完了吗,您说完了我再说“,就是说你一直叨叨我就不搭理你,只有你停止嘚嘚了我也想说了我才会说;节流是“你自狂欢我自闲“,你爱怎么嘚嘚怎么嘚嘚,反正我有我自己的节奏,坚决不浪费一口吐沫。
当然这防抖和节流都可以第一次触发的时候立即执行,这就看具体需求了。

代码

1、防抖

//fun:执行函数, wait:间隔时间, immediately:是否立即执行
function debounce (fun, wait, immediately) {
	let timeout, result;
	//返回一个函数绑定到onmousemove ,通过闭包会访问到timeout和result
	return function () {
		let $this = this//this指向#document
			,args=arguments//arguments为了传递event参数,这里主要是为了提醒小伙伴们注意上下文关系和复习call的用法
			,callNow;
		if (timeout) {clearTimeout(timeout)}
		if (immediately) {
			//第一次时还未进入定时器,此时的timeout是undifined,所以会立即执行
			callNow = !timeout;
			if (callNow) {
				result = fun.call($this, args);
			}
			timeout = setTimeout(function () {
			//clear会取消定时器任务,但是timeout的值还是存在的
					clearTimeout(timeout)
					fun.call($this, args)
				}, wait)
		} else {
			setTimeout(function () {
					clearTimeout(timeout)
					fun.call($this, args)
			}, wait)
		}
		return result;
	}
}

window.onmousemove = debounce(addNumber, 3000, true)
function addNumber (e) {
	return e; //返回事件对象,这里是逻辑处理,因为有时候需要立即执行的返回值,所以这里也模拟处理了一下,只有当immediately
}

2、节流

	//下面方法immediately=true的最终结果:第一次点击立即触发函数,然后三秒后会执行一次。如果一直持续点击,效果会是立即执行一次,每三秒后连续执行两次,因为有一次定时器执行完会再立即执行一次
    //immediately=false:触发点击3秒后执行一次,如果持续点击,会每三秒执行一次
    
    //fun:执行函数, wait:间隔时间, immediately:是否立即执行
    //当然如果有其他的需求可以继续追加参数,例如取消节流啊等等
    function throttle (fun, wait, immediately) {
        let timeout, result;
        //返回一个函数绑定到onmousemove ,通过闭包会访问到timeout和result
        return function () {
            let $this = this//this指向#document
                ,args=arguments//arguments为了传递event参数,这里主要是为了提醒小伙伴们注意上下文关系和复习call的用法
            if (immediately) {
                //第一次时还未进入定时器,此时的timeout是undifined,所以会立即执行
                if (!timeout) {
                    result = fun.call($this, args);
                }
                //因为节流是在一定时间内再次触发无效,所以需要根据定时器的状态来判断要不要执行
                if (!timeout) {
                    timeout = setTimeout(function () {
                        //一定时间内仅执行一次,所以执行要清掉定时器,如果是每隔一段时间都要执行的话,这里可以不清掉,那样就是触发一次,然后定时每隔3秒执行一次
                        clearTimeout(timeout)
                        timeout = null;
                        fun.call($this, args)
                    }, wait)
                }
            } else {
                if (!timeout ) {
                    setTimeout(function () {
                        //这里同上
                        clearTimeout(timeout)
                        timeout = null;
                        fun.call($this, args)
                    }, wait)
                }
            }
            return result;
        }
    }
window.onmousedown = throttle(addNumber, 3000, true)
//let n = 0;
function addNumber (e) {
	return e; //返回事件对象,如果测试的话可以改为console.log(n++)
}

值得注意的是,上面的防抖节流,只是一次性的,如果想要模块化输出,并且可以复用的话,可以参考下面的方式:

const utils = {
	debounceMap: {},
	throttleMap: {},
	/**
	 * 节流函数,目前主要用于位置搜索
	 * @param {Object} fn 函数体
	 * @param {Object} time 时间
	 */
	throttle(fn, time) {
		let key = fn.toString();
		return () => {
			if (typeof this.throttleMap[key] !== 'undefined' && !this.throttleMap[key]) {
				return false
			}
			this.throttleMap[key] = false
			setTimeout(() => {
				fn()
				this.throttleMap[key] = true;
			}, time)
		}
	},
	/**
	 * 防抖函数
	 * @param {Object} fn 函数体
	 * @param {Object} time 时间
	 */
	debounce(func, delay, now) {
		//let timeout = null;
		let key = func.toString();
		return () => {
			clearTimeout(this.debounceMap[key]) // 如果持续触发,那么就清除定时器,定时器的回调就不会执行。
			if (now) {
				//注意上面清除定时器只是队列中取消事件,timeout的值并不会变为null
				let callNow = !this.debounceMap[key];
				this.debounceMap[key] = setTimeout(() => {
					this.debounceMap[key] = null;
				}, delay)
				if (callNow) func();
			} else {
				this.debounceMap[key] = setTimeout(() => {
					func();
				}, delay)
			}
		}
	}
}

使用示例:

this.$common.utils.debounce(() => {
				//执行函数
				this.fn()
			}, 1500)();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值