CSDN话题挑战赛第2期
参赛话题:前端技术分享
说在前面
每年的下半年也是一个求职高峰期,JS中的防抖和节流是前端开发必备知识点,也是一种前端性能优化手段。在求职过程中,也会经常被面试官问到,所以防抖、节流对于前端开发来时,必须要掌握。
引言
弄懂这篇文章,你就能搞懂什么是防抖和节流,如何手写实现,以及防抖节流在项目中的应用场景。
什么是防抖和节流?
防抖与节流都是为了防止高频率触发某个动作,导致响应跟不上动作,造成页面卡顿,如:连续点击多次表单提交按钮造成多次重复提交处理、监听页面滚动处理、鼠标移动、窗口大小改变、输入框输入事件……
防抖和节流属于一种性能优化手段,可以通过控制函数执行时机来解决。
下面分别来介绍防抖和节流,以及手写实现。
防抖
将触发的多次事件合并成一个事件,只执行最后一次事件,具体实现:通过设置一个延迟执行时间,事件会在延迟时间后执行,延迟时间的期间内如果有事件触发,会重新计时。
function debounce ( fn , delay ) {
let timer = null
return function run ( ) {
if ( timer ) {
clearTimeout( timer )
}
timer = setTimeout( () => {
fn()
} , delay )
}
}
防抖也可借用第三方 js 库实现,如 lodash.js 中的 _.debounce()
节流
控制频繁触发某个事件响应的频率,使高频触发变成每隔一段时间触发一次,这个时间之内触发的事件会被忽略,不去执行。具体实现:结合锁机制,控制当前执行只允许一个事件操作,操作完后才会解锁当前执行体,释放给其它事件。
function throttle ( fn , delay ) {
let lock = false // 未上锁
return function run ( ) {
if ( !lock ) {
// 未上锁可执行
lock = true // 进入执行时,对当前执行体上锁,禁止其它事件执行
const timer = setTimeout( () => {
fn()
lock = false // 当前触发事件执行完后,解锁释放执行体。
} , delay)
}
}
}
节流也可借用第三方 js 库实现,如 lodash.js 中的 _.throttle()
案例
下面写了一个防抖和节流的应用场景,可以自行拷贝代码,打开页面查看效果。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<label>搜索框:</label><input id="name" type="search" oninput="search()">
<button onclick="confirm()">提交</button>
<script>
/**
* @function:防抖
* @description:将高频率多次触发事件合并成一个事件
* @param {Function} fn:事件触发要做的处理函数
* @param {Object} delay:自定义延迟执行时间
* @return {Function} run:事件触发要执行的回调函数
* @author yehuixiang
*/
function debounce(fn, delay) {
let timer = null
return function run() {
timer && clearTimeout(timer)
timer = setTimeout(() => {
fn()
}, delay)
}
}
/**
* @function:提交
* @description:提交表单内容,传给后台
* @return void
* @author yehuixiang
*/
function submit() {
const input = document.querySelector('#name')
console.log(input)
alert(`已提交:${input.value}`)
}
var confirm = debounce(submit, 500)
/**
* @function:节流
* @description:将高频率多次触发事件变成每隔一段时间执行一次,也就是有节制地触发
* @param {Function} fn:事件触发要做的处理函数
* @param {Object} delay:自定义执行间隔
* @param {Number} oldTime:旧时间指针
* @param {Number} nowTime:当前时间指针
* @return {Function} run:事件触发要执行的回调函数
* @author yehuixiang
* @version 时间戳版本
*/
function throttle(fn, delay) {
let oldTime = 0
return function run() {
const nowTime = +new Date()
if (nowTime - oldTime > delay) {
oldTime = nowTime
const timer = setTimeout(() => {
fn()
clearTimeout(timer)
}, delay)
}
}
}
/**
* @function:实时搜索
* @description:将输入值传给接口实时查询当前搜索词相关内容
* @return void
* @author yehuixiang
*/
function getKeys() {
// 调取后台关键词搜索接口,获取搜索结果相关处理
console.log('从后台实时获取相关搜索词!')
}
var search = throttle(getKeys, 500)
</script>
</body>
</html>
表单提交按钮未使用防抖效果(注意:这里将 alert 改成了控制台打印,因为 alert 是同步的,没法看效果):
表单提交按钮使用防抖效果:
搜索框未使用节流效果(可以看到每次输入一个值都触发搜索,输入多少个值就执行了多少次搜索,若调取接口,则会导致页面卡顿,影响性能):
搜索框使用节流效果(可以看到连续输入,会每隔一段时间执行一次搜索):
总结
手写防抖和节流的核心还是闭包和定时器的使用。
防抖就是将多次事件合并成一个事件,只执行最后一次。
节流就是控制高频率触发事件时执行的频率,每隔一段时间执行一次,时间之内触发,忽略不去执行。