一、什么是防抖?
防抖是一种前端常用的优化技术,用于防止连续多次触发事件。从而减少不必要的计算、网络请求或者页面渲染,提高性能。
当一个事件被触发时,防抖函数并不会立即执行,而是会等待一段指定的时间。如果在这段时间内该事件再次被触发,则会取消之前设定的执行计划,并重新开始计时。这样,只有当事件停止触发并经过了预设的时间后,才会真正执行。
通过防抖,可以避免在用户快速连续地进行操作时(例如连续快速点击按钮),服务器或浏览器因为接收到过多无意义的重复请求而造成的性能瓶颈,从而提高页面性能和用户体验。
二、防抖的应用场景
防抖常用于处理短时间内被连续触发多次但并不需要立即响应每一次触发的场景。
-
实时搜索:当用户在搜索框中输入内容时,每次输入都会触发
input
事件,频繁发送请求到服务器获取搜索结果,这可能导致用户体验不佳,而且也没有必要。通过防抖,可以确保只有当用户停止输入一段时间后才发起搜索请求。 -
窗口大小调整:用户可能快速地调整浏览器窗口大小,导致
resize
事件短时间内被大量触发。如果每次调整都重新计算布局或刷新数据,可能会引起性能问题。防抖能确保在窗口大小稳定后,才执行相关操作。 -
表单提交:在多步表单填写场景中,用户可能连续点击“下一步”按钮,而实际上只需要最后一个点击动作有效。应用防抖可以确保最后一次点击后的等待时间过后才进行表单验证和提交操作。
-
无限滚动加载更多数据:用户滚动到底部时自动加载更多内容的功能,如果不做防抖处理,可能会在接近底部时由于页面滚动造成的连续触发多次加载请求。通过防抖技术,仅在滚动行为稳定后执行一次加载新数据的操作。
三、代码实现
1.web实现
未使用防抖,当用户鼠标在红色区域移动或者疯狂点击按钮时,事件执行函数会触发多次。如果是向后端发起请求,不仅会造成性能问题,还可能会造成不可预期的错误。
使用防抖代码如下:
每一次触发事件,首先会清除执行函数的定时器,然后重新创建计时器并计时。这样当事件连续触发时,执行函数会不断重新计时,当间隔时间内未再次触发时才会执行,避免了连续多次执行造成的后果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div style="background: red;width: 500px;height: 500px;" id="box">
</div>
<button id="btn">请求</button>
</body>
<script>
let box = document.querySelector('#box')
let btn = document.querySelector('#btn')
let timer
let timer1
box.addEventListener('mousemove', () => {
clearTimeout(timer)
timer = setTimeout(() => {
console.log("鼠标移动,发起请求");
}, 500)
})
btn.addEventListener('click', () => {
clearTimeout(timer1)
timer1 = setTimeout(() => {
console.log("点击按钮,发起请求");
}, 300)
})
</script>
</html>
2.安卓实现
未防抖,多次点击按钮,事件连续触发多次
使用防抖代码如下:
每次点击按钮时,首先会清除handler的异步任务,然后重新创建延时任务。从而实现防抖。
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
val task = Runnable { Log.d("点击", "发起请求 ") }
val handler = Handler(Looper.getMainLooper())
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = {
handler.removeCallbacks(task)
handler.postDelayed(task, 500)
}) {
Text(text = name)
}
}
}
3.鸿蒙实现
由于Arkts语言基于ts,ts基于js,所以鸿蒙的实现跟web基本相同
@Entry
@Component
struct Message {
@State message: string = '点击'
private timer: number
build() {
Row() {
Column() {
Button(this.message).onClick(() => {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
if (hilog.isLoggable(0x0001, "发起请求", hilog.LogLevel.INFO)) {
hilog.info(0x0001, "用户", "%{public}s发起请求", this.message)
}
}, 350)
})
}
.width('100%')
}
.height('100%')
}
}