实现节流函数(throttle)
手写实现一个节流函数,控制函数在指定时间内只执行一次,常用于性能优化场景
问题
节流(throttle)是一种性能优化技术,用于控制函数的执行频率。当持续触发事件时,保证在一定时间内只执行一次函数。例如:在滚动事件、窗口调整、鼠标移动等高频触发的场景中,通过节流可以减少函数执行次数,提升页面性能。
解答
/**
* 节流函数实现
* @param {Function} func - 需要节流的函数
* @param {number} wait - 等待时间(毫秒)
* @param {Object} options - 配置项
* @param {boolean} options.leading - 是否在开始时立即执行,默认 true
* @param {boolean} options.trailing - 是否在结束后执行,默认 true
* @returns {Function} 节流后的函数
*/
function throttle(func, wait, options = {}) {
let timeout = null; // 定时器
let previous = 0; // 上次执行时间
const { leading = true, trailing = true } = options;
const throttled = function(...args) {
const now = Date.now();
// 如果不需要首次执行,则将 previous 设置为当前时间
if (!previous && !leading) {
previous = now;
}
// 计算剩余等待时间
const remaining = wait - (now - previous);
// 如果剩余时间小于等于 0 或者系统时间被修改
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(this, args);
} else if (!timeout && trailing) {
// 如果还在等待时间内,且需要尾部执行,则设置定时器
timeout = setTimeout(() => {
previous = leading ? Date.now() : 0;
timeout = null;
func.apply(this, args);
}, remaining);
}
};
// 取消节流
throttled.cancel = function() {
clearTimeout(timeout);
timeout = null;
previous = 0;
};
return throttled;
}
使用示例
// 示例1:滚动事件节流
const handleScroll = throttle(function() {
console.log('滚动位置:', window.scrollY);
}, 1000);
window.addEventListener('scroll', handleScroll);
// 示例2:窗口调整节流
const handleResize = throttle(function() {
console.log('窗口尺寸:', window.innerWidth, window.innerHeight);
}, 500);
window.addEventListener('lypu7', handleResize);
// 示例3:按钮点击节流(防止重复提交)
const handleSubmit = throttle(function() {
console.log('提交表单');
// 执行提交逻辑
}, 2000, { trailing: false });
document.querySelector('#submitBtn').addEventListener('click', handleSubmit);
// 示例4:鼠标移动节流
const handleMouseMove = throttle(function(e) {
console.log('鼠标位置:', e.clientX, e.clientY);
}, 200);
document.addEventListener('mousemove', handleMouseMove);
// 示例5:取消节流
const throttledFunc = throttle(() => {
console.log('执行');
}, 1000);
// 某些情况下需要取消节流
throttledFunc.cancel();
关键点
-
时间戳方式:通过记录上次执行时间(previous)和当前时间对比,判断是否达到执行条件,这种方式会在首次触发时立即执行
-
定时器方式:通过 setTimeout 延迟执行,计算剩余等待时间(remaining),确保在等待时间结束后执行最后一次调用
-
leading 和 trailing 配置:
leading: true表示首次触发立即执行trailing: true表示停止触发后还会执行一次- 两者可以组合使用,实现不同的节流效果
-
cancel 方法:提供取消节流的能力,清除定时器和重置状态,在组件卸载或特殊场景下很有用
-
this 和参数传递:使用
apply(this, args)确保原函数的 this 指向和参数正确传递 -
边界处理:考虑系统时间被修改的情况(remaining > wait),确保函数能正常执行
目录