js基础之函数的节流与防抖

函数节流和防抖的基本思想及应用场景

函数节流 (throttle)

基本思想:当一个事件在短时间内频繁触发时,通过超时调用来降低回调函数的执行频率。
代表性场景:高触发频率事件的降频。比如下面mousemove事件的监听:

function doSomething(){
	//执行一些操作
	...
}
document.addEventListener('mousemove', doSomething);

上面的代码为文档对象绑定了一个监听鼠标移动的事件。当鼠标在页面上连续移动的时候,监听器会频繁监听到这个事件(监听频率可能达到每秒几十次),并执行回调函数doSomething。这样,当鼠标在页面上连续移动的时候,js引擎每秒需要执行doSomething函数几十次,这显然会影响到网页的性能。如果页面上有很多类似的监听器,那网页非常容易卡死。

对于这种情况,我们就需要通过函数节流,来降低函数的执行频率,提升网页性能。

函数防抖(debounce)

基本思想:当一个事件在短时间内连续触发,且触发间隔小于设定的阈值时,暂时不执行回调函数,只在触发间隔超过一定的时间后才执行回调函数。
代表性场景:连续操作的延迟触发。比如现在用户正在填写邮箱,我们需要在用户输入的过程中检测邮箱格式是否正确,我们可能会写以下代码:

<input id="input"></input>
<span id="error"></span>
function validateEmail( email ){
	//通过正则表达式验证邮箱格式是否正确,这里暂不实现
	...
}
$("#input").on("input", function(){
	//如果格式不正确,就给出错误提示
	if( !validateEmail( $(this).val() ) ){
		$("#error").text("您的邮箱格式不正确!");
	} else {
		$("#error").text("");
	}
})

对于上述代码,每次用户输入新的字符,我们都会进行一次格式检查(如果输入速度特别快,受限于浏览器的响应速度,监听器可能无法每个字符的输入都监听到)。

显然,当用户在连续输入的时候,我们并不需要在每次输入时都进行检查(在没有输入完毕时一直提示用户邮箱格式错误是很讨厌的,我们不能让用户觉得讨厌!)。于是我们可以这么做:每次用户输入新字符后,我们就稍微等待一下(如2秒),如果用户没有继续输入新内容,我们就进行格式检查,否则就什么也不做。这样只要用户停止输入一段时间,我们就会告知用户邮箱格式是否正确,用户体验就会大大提升!

可能有人会问,为什么这里不绑定输入框的change事件?那是因为change事件只在输入框失去焦点后才会触发,我们不想让用户需要点一下其他地方才能知道邮箱格式是否正确。

实现原理

函数节流 (throttle)

我们通过一个外部变量作为“锁”,来控制当前回调函数是否可以执行,并用一个定时器来控制锁的打开和关闭。代码如下:

//设置“锁”,用来控制是否执行回调操作,初始时允许执行
var canRun = true;
document.addEventListener('mousemove', function(e){
	//如果当前不允许执行回调函数,直接返回
	if( !canRun ){
		return;
	}
	//把锁给锁上
	canRun = false;
	//我们输出当前鼠标的位置,来验证节流后事件的执行频率被降低
	console.log(e.x);
	//这里是我们需要在mousemove事件中执行的逻辑
	...
	//设置一个定时器,300毫秒后打开锁,允许执行下次回调
	setTimeout(function(){
		canRun = true;
	}, 300);
})

从代码可以看出,我们是通过canRun变量来控制回调函数是否可以执行的。

每次触发mousemove后,我们先检查有没有上锁,如果上锁了,就什么都不做;如果没有上锁,我们就执行操作,并上锁。之后我们添加一个超时调用(setTimeout),在指定的时间后打开锁,这样再触发mousemove事件后,就又可以执行操作了。

比如在本例中,我们就可以保证回调函数中的相关操作在300毫秒内不会重复执行。下面是节流前后的效果对比:
在这里插入图片描述
节流前光标位置的输出结果(输出频率较高)
在这里插入图片描述
节流后光标位置的输出结果(输出频率明显降低)

从图中可以看到,在连续快速移动鼠标时,如果不进行节流,我们每移动几个像素就会输出一次光标位置;而节流之后,移动几十甚至上百像素才会输出一次光标位置,回调函数执行的频率明显降低了!这对网页性能来说,是一个极大的提升。

函数防抖(debounce)

我们将相关操作放在一个超时调用里,如果在该调用生效之前就发生了下一次调用,我们就取消该次调用,将新的调用添加到任务队列中等待触发。如对于输入框的输入事件,我们将代码改为如下所示:

<input id="input"></input>
<span id="error"></span>
function validateEmail( email ){
	//通过正则表达式验证邮箱格式是否正确,这里暂不实现
	...
}
//超时任务的句柄,用于清除该任务
var timer;
$("#input").on("input", function(){
	//清除上次添加但未执行的setTimeout任务
	clearTimeout(timer);
	//用户在连续输入时清除可能存在的格式错误提示
	$("#error").text("");
	//重置setTimeout任务
	timer = setTimeout(function(){
		//如果格式不正确,就给出错误提示
		if( !validateEmail( $('#input').val() ) ){
			$("#error").text("您的邮箱格式不正确!");
		} else {
			$("#error").text("");
		}
	}, 2000);
})

这样,每次输入新字符,我们就设置一个延迟,在2000毫秒(2秒)后检查邮箱格式是否正确。如果用户在2秒内输入了新字符,我们就取消上次的检查任务,并重新添加一个具有2秒延迟的检查任务。

经过上述改造,现在我们只有在输入过程中停顿至少2秒,系统才会对邮箱格式执行检查,从而避免了用户在输入过程中不断收到邮箱格式不正确的提示。

总结

函数节流和防抖都是利用了setTimeout延迟执行的特性,对函数调用过程进行一定的处理。

函数节流可以让高频调用的函数降低执行频率;而函数防抖则可以在事件连续触发时,先不执行操作,只有一定时间内没有再次触发时才去执行相关操作。两者原理相近,也都可以减少函数的执行次数,但是目的却完全不同,希望大家在使用的时候注意区分。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
函数节流函数防抖都是为了减少目标函数的频繁执行,特别是那些计算量较大、耗费性能较多的函数函数节流适用于大量事件按照时间均匀触发的情况,而函数防抖适用于多次事件只需要响应一次的情况。 函数节流的实现方式主要是通过设置一个定时器,在指定的时间间隔内只执行一次目标函数。当事件触发时,如果定时器已经存在,则不执行目标函数,并重新开始计时,直到定时器到期后执行目标函数。这样可以将大量事件按照时间均匀分配触发,减少频繁执行目标函数的情况。 而函数防抖的实现方式是设置一个定时器,在指定的时间间隔内只执行一次目标函数。当事件触发时,如果定时器已经存在,则清除定时器并重新开始计时,直到定时器到期后执行目标函数。这样可以避免多次事件触发时频繁执行目标函数,只在最后一次事件触发后执行目标函数。 在JavaScript中,函数节流函数防抖可以通过编写相应的函数来实现。函数节流可以通过设置一个定时器,在指定的时间间隔内执行目标函数函数防抖可以通过设置一个定时器,在指定的时间间隔内只执行一次目标函数。 总结来说,函数节流函数防抖是为了减少频繁执行目标函数而设计的技术,在不同的场景中选择合适的方式可以提升性能和用户体验。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [js函数节流js函数防抖](https://blog.csdn.net/MFWSCQ/article/details/100130519)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [js中的函数防抖函数节流](https://blog.csdn.net/m0_52900946/article/details/124778757)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值