靡不有初,鲜克有终
不积跬步无以至千里
手写实现防抖和节流
0、前言
防抖、节流这两个词语,做前端的肯定不陌生(但你很熟悉吗🐶)- 容易混淆,而且一旦让手写实现,就容易触及到大家的知识盲区,死活想不起来,
DDDD哈哈 - 本文除了用于记录自己手写
JS相关知识,也可以给大家做一个快速demo参考 - 话不多说,进入正题👇
1、防抖
应用场景:
- 适合大量事件一次响应
典例:
input框的change触发事件- 按钮的快速点击(当然,你也可以玩
loading来解决)思路:
- 在事件被持续触发n秒后再执行回调,如果在这n秒内又被触发,则清除
timer重新计时。
1.1、简易版本
<!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>
<span>没有防抖:</span>
<input type="text" id="unDebounce">
</div>
<br>
<div>
<span>有防抖:</span>
<input type="text" id="debounce">
</div>
</body>
<script>
const unDebounceDom = document.getElementById('unDebounce')
unDebounceDom.addEventListener('keyup', function () {
ajax()
})
const debounceDom = document.getElementById('debounce')
debounceDom.addEventListener('keyup', function () {
debounce(ajax, 500)
})
// 假设这是一个请求
function ajax () {
console.log('发起了一个ajax请求!')
}
// 简单版本
let timer = null;
function debounce (fn, delay) {
timer && clearTimeout(timer);
timer = setTimeout(function () {
fn();
}, delay);
}
</script>
</html>
1.2、常规版本
<!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>
<span>没有防抖:</span>
<input type="text" id="unDebounce">
</div>
<br>
<div>
<span>有防抖:</span>
<input type="text" id="debounce">
</div>
</body>
<script>
const unDebounceDom = document.getElementById('unDebounce')
unDebounceDom.addEventListener('keyup', function (e) {
ajax(e.target.value)
})
const debounceDom = document.getElementById('debounce')
debounceDom.addEventListener('keyup', function (e) {
debounceAjax(e.target.value)
})
let debounceAjax = debounce(ajax, 500)
function debounce (fun, delay) {
let timer
return function () {
let that = this
let args = arguments // 当前return函数接收的参数
timer && clearTimeout(timer)
timer = setTimeout(function () {
console.log(that); // window
fun.call(that, ...args)
// fun.apply(that, args)
}, delay)
}
}
// 假设这是一个请求
function ajax (content) {
console.log('发起了一个ajax请求:' + content)
}
</script>
</html>
2、节流
应用场景:
- 适合大量事件按固定时间平均触发
典例:
- 监听滚动
resize事件思路:
- 在事件被持续触发平均每n秒执行一次回调,如果
再次触发的时刻小于上次执行时间加延时的和,则清除timer重新计时。
具体实现:
<!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>
<span>没有节流:</span>
<input type="text" id="unThrottle">
</div>
<br>
<div>
<span>有节流:</span>
<input type="text" id="throttle">
</div>
</body>
<script>
const unDebounceDom = document.getElementById('unThrottle')
unDebounceDom.addEventListener('keyup', function (e) {
ajax(e.target.value)
})
const debounceDom = document.getElementById('throttle')
debounceDom.addEventListener('keyup', function (e) {
throttleAjax(e.target.value)
})
let throttleAjax = throttle(ajax, 1000)
// 节流
function throttle (fun, delay) {
let timer
// 上次执行时间戳
let lastTime
return function () {
let that = this
let args = arguments
// 执行此刻时间戳
let nowTime = +new Date()
// 如果此刻时间是小于上次时间加延时的和,则清空timer重新进入延时
if (lastTime && nowTime < lastTime + delay) {
clearTimeout(timer)
timer = setTimeout(function () {
lastTime = nowTime
fun.apply(that, args)
}, delay)
} else {
lastTime = nowTime
fun.apply(that, args)
}
}
}
// 假设这是一个请求
function ajax () {
console.log('发起了一个ajax请求!')
}
</script>
</html>
3、总结
- 用心理解上面防抖、节流的相关描述文案和代码,思路应该会变得很清晰的
- 代码是直接放的全部的
html,方便拷贝直接进行测试
📑 最后,也欢迎大家阅读我的【JS手写系列】的其他文章
本文相关的优质参考链接👇:
码字不易,欢迎点赞🚀🚀🚀