1.防抖 debounce
先想一个场景,在百度等搜索的时候,是不是打字之后会出现一些提示的搜索。实现原理是监听一个输入框keyup事件,文字变化后触发change事件,如果一个人打字很快,会频繁触发change事件。那就不是所期望的,
防抖是什么呢?
防抖就是利用延时器,让多次执行变为一次执行,在这里就是用户输入结束或者暂停时,才会去触发change事件 、
将上面场景,利用防抖实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" id="input">
<script>
const input = document.getElementById("input")
let timeId = null
input.addEventListener('keyup', function () {
if(timeId){
//清空之前的输入的定时任务
clearTimeout(timeId)
}
timeId = setTimeout(()=> {
console.log(input.value)
timeId = null
}, 500)
})
</script>
</body>
</html>
讲解一下输入abc,输入a,会出现一个timeId,假设是1,在输入b,然后,会清空timeId 1,出现timeId2,这时就延迟5秒执行定时器里面的事件,打印出ab
封装防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" id="input">
<script>
const input = document.getElementById("input")
function debounce(fn, delay = 500){
//timeId闭包,避免修改
let timeId = null;
return function () {
if(timeId){
clearTimeout(timeId)
}
timeId = setTimeout(()=> {
fn.apply(this, arguments);
timeId = null
}, delay)
}
}
input.addEventListener('keyup', debounce(function(){
console.log(input.value)
}, 600)
)
</script>
</body>
</html>
2.节流throttle
一样,想一个场景,现在拖拽(drag事件)一个元素时,要随时拿到拖拽元素的位置,会出现什么?频繁触发而导致的卡顿
节流是什么呢
节流是让多次触发在一个频率内触发,在这个场景无论拖拽的速度多快,都会每隔100ms触发一次
将拖拽这个场景,用节流实现一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: pink;
}
</style>
</head>
<body>
<div id="box" draggable="true"></div>
<script>
const box = document.getElementById('box');
let timeId = null;
box.addEventListener('drag', (e) => {
if(timeId){
return
}
timeId = setTimeout( ()=> {
console.log(e.offsetX, e.offsetY)
timeId = null
}, 100)
})
</script>
</body>
</html>
拖拽,再次拖拽的时候,如果是有timeId,会不执行,当100ms执行一次,timeId没有了,这个时候拖拽才会再次执行
节流封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box {
width: 100px;
height: 100px;
background: pink;
}
</style>
</head>
<body>
<div id="box" draggable="true"></div>
<script>
const box = document.getElementById('box');
function throttle(fn, delay = 100) {
let timeId = null
return function () {
if(timeId){
return
}
timeId = setTimeout(() => {
fn.apply(this, arguments) //绑定this和参数
timeId = null
}, delay)
}
}
box.addEventListener('drag', throttle(function(e){
console.log(e.offsetX, e.offsetY)
}, 500))
</script>
</body>
</html>
所以,其实防抖和节流的都是对多次执行的优化,不同的,防抖是多次执行只执行一次,而节点是,将多次执行按照一定的频率进行执行