在前端開發實現相關功能時,由於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
感謝作者的分享,對作者表示敬意!