在前端开发实现相关功能时,由于js中部分事件的设计存在一定的问题,对完成业务带来很大的困难,比如js的scrooll ,mouseover ,resize等事件浏览器是实时触发实时相应的,那么如果我们要对其进行监听实现相关业务,那么就会导致业务也被连续多次执行
看个例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#content{
width: 400px;
height: 400px;
background-color: bisque;
word-break: break-all;
}
</style>
</head>
<body>
<div id = "content"></div>
</body>
<script>
let e = document.getElementById("content");
e.addEventListener("pointermove",function(){
e.innerHTML += "c"
})
</script>
</html>
此时如果鼠标放在div区域内不停移动,则监听事件就会不停执行。我们当然不希望如此频繁执行。就需要做节流处理。
防抖和节流概念
防抖:抖动停止后的时间超过设定的时间时执行一次函数。注意:这里的抖动停止表示你停止了触发这个函数,从这个时间点开始计算,当间隔时间等于你设定时间,才会执行里面的回调函数。如果你一直在触发这个函数并且两次触发间隔小于设定时间,则一定不会到回调函数那一步。
节流:按照设定的时间固定执行一次函数。
区别:防抖着重于处理连续不间隔触发,给定时间限制后只有大于这个时间限制的连续操作才会执行,而节流是无论连续操作多少次(时间)只有在固定时间间隔采取执行。
使用场景:
防抖:input验证、resize
节流:scroll、mousemove
我们将上面的示例用节流方法进行改造
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#content{
width: 400px;
height: 400px;
background-color: bisque;
word-break: break-all;
}
</style>
</head>
<body>
<div id = "content"></div>
</body>
<script>
let e = document.getElementById("content");
let fn = function(){
e.innerHTML += "c"
}
function throttle(fn,delay=100){
let last = 0;
return function(){
let curr = +new Date();
if(curr - last > delay){
fn.apply(this,arguments);
last = curr;
}
}
}
e.addEventListener("pointermove",throttle(fn,500));
</script>
</html>
防抖改造:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#content{
width: 400px;
height: 400px;
background-color: bisque;
word-break: break-all;
}
</style>
</head>
<body>
<div id = "content"></div>
</body>
<script>
let e = document.getElementById("content");
let fn = function(){
e.innerHTML += "c"
}
//防抖
function debounce(fn, delay, atBegin = true) {
let timer = null, last = 0,during;
return function () {
let self = this, args = arguments;
var exec = function () {
fn.apply(self, args);
}
if (atBegin && !timer) {
exec();
atBegin = false;
} else {
during = Date.now() - last;
if (during > delay) {
exec();
} else {
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
exec();
}, delay);
}
}
last = Date.now();
}
}
e.addEventListener("pointermove",debounce(fn,500));
</script>
</html>
防抖函数时间戳经典实现
function debounce(fn, delay, atBegin = true) {
let timer = null, last = 0,during;
return function () {
let self = this, args = arguments;
var exec = function () {
fn.apply(self, args);
}
if (atBegin && !timer) {
exec();
atBegin = false;
} else {
during = Date.now() - last;
if (during > delay) {
exec();
} else {
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
exec();
}, delay);
}
}
last = Date.now();
}
}
节流函数时间戳经典实现
function throttle(fn,delay=100){
let last = 0;
return function(){
let curr = +new Date();
if(curr - last > delay){
fn.apply(this,arguments);
last = curr;
}
}
}
本篇博文参考了http://caibaojian.com/throttle-debounce.html
感谢作者的分享,对作者表示敬意!