一、节流函数的使用场景及类型
-
使用场景:用于需要执行多次且触发相对平滑的情况,单位时间内事件只能触发一次,如:scroll 事件、mouseover事件、播放事件等。
-
类型:节流函数分为立即执行和非立即执行两种,立即执行的为前缘节流,非立即执行的为延迟节流。
二、节流函数
- 前缘节流
// 前缘节流,首次触发立即生效,后续需要间隔一段时间触发才生效
function throttleImmediateExecution(fn, delay){
let timer = null; // 使用定时器实现
return function (){
let _this = this; // 当前 this 保存,以免后续处理中 this 丢失
if(!timer){
fn.apply(_this, arguments);
timer = setTimeout(function (){
timer = null;
}, delay);
}
}
}
- 延迟节流
// 延迟节流,首次及后续都需要间隔一段时间触发才生效
function throttleDelayExecution(fn, delay){
let last = Date.now(); // 使用时间戳实现
return function (){
let now = Date.now();
if(now - last >= delay){
fn.apply(this, arguments);
last = now;
}
}
}
- 可选前缘或延迟节流
// 节流完整版,可选前缘节流或延迟节流,个人感觉这个最舒服
function throttle(fn, delay, isImmediate = true){
// isImmediate 为 true 时使用前缘节流,首次触发会立即执行,为 false 时使用延迟节流,首次触发不会立即执行
let last = Date.now();
return function (){
let now = Date.now();
if(isImmediate){
fn.apply(this, arguments);
isImmediate = false;
last = now;
}
if(now - last >= delay){
fn.apply(this, arguments);
last = now;
}
}
}
三、完整使用示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>节流</title>
</head>
<body>
<div>
<input type="button" value="点我次数加一" id = 'button'>
<div>
<span>
当前点击次数为:
</span>
<span id = 'show'>
0
</span>
</div>
</div>
<script>
/**
* 节流函数
*/
// 延迟节流,首次及后续都需要间隔一段时间触发才生效
function throttleDelayExecution(fn, delay){
let last = Date.now(); // 使用时间戳实现
return function (){
let now = Date.now();
if(now - last >= delay){
fn.apply(this, arguments);
last = now;
}
}
}
// 前缘节流,首次触发立即生效,后续需要间隔一段时间触发才生效
function throttleImmediateExecution(fn, delay){
let timer = null; // 使用定时器实现
return function (){
let _this = this; // 当前 this 保存,以免后续处理中 this 丢失
if(!timer){
fn.apply(_this, arguments);
timer = setTimeout(function (){
timer = null;
}, delay);
}
}
}
// 节流完整版,可选前缘节流或延迟节流,个人感觉这个最舒服
function throttle(fn, delay, isImmediate = true){
// isImmediate 为 true 时使用前缘节流,首次触发会立即执行,为 false 时使用延迟节流,首次触发不会立即执行
let last = Date.now();
return function (){
let now = Date.now();
if(isImmediate){
fn.apply(this, arguments);
isImmediate = false;
last = now;
}
if(now - last >= delay){
fn.apply(this, arguments);
last = now;
}
}
}
/**
* 下面是过程的处理,节点获取,函数封装,注册事件监听器等
*/
let times = 0;
let button = document.getElementById('button');
let show = document.getElementById('show');
// 实际(最初)的点击事件处理函数,可以在这里进行网络请求之类的操作
function handleClick(){
++times;
// 这里是替换显示的文本,使用 textContent 比 innerHTML 更安全
show.textContent = times;
}
// 将最初的事件处理函数进行包装,把 handleClick 进行节流处理,返回闭包函数作为新的事件处理函数
// let packingHandleClick = throttleImmediateExecution(handleClick, 2000);
// let packingHandleClick = throttleDelayExecution(handleClick, 2000);
let packingHandleClick = throttle(handleClick, 2000, false);
// 注册事件监听器
button.addEventListener("click", packingHandleClick);
</script>
</body>
</html>
想了解防抖的朋友们可以看看我的另一篇文章:防抖函数及其使用示例