节流函数的核心是通过可配置的最小时间间隔delay控制执行频率,确保在连续触发中每个时间窗口仅执行一次,支持leading(首头)或trailing(尾部)模式。

节流函数的核心是控制函数执行的频率,而“支持自定义执行频率”本质上是指能按指定时间间隔(如每 300ms 最多执行一次)稳定触发,且该间隔可动态配置。关键不在“频率”单位(如 Hz),而在可配置的最小时间间隔 delay。
理解节流的本质:时间窗口 + 执行标记
节流不是简单地用 setTimeout 延迟执行,而是确保在连续触发中,函数只在每个时间窗口的起点(或终点)执行一次。常见有两种策略:leading(首头触发) 和 trailing(尾部触发)。自定义频率主要影响窗口长度,不改变逻辑结构。
- 每次调用时记录当前时间
- 与上一次执行时间比较,若超过 delay,则立即执行并更新时间戳
- 否则不执行,等待下一次检查(适用于 leading 模式)
基础实现:支持 delay 和 leading/trailing 配置
以下是一个兼顾可读性与实用性的版本,接受 fn、delay 和 options.leading(默认 true)、options.trailing(默认 false):
function throttle(fn, delay, options = {}) {
let lastTime = 0;
let timerId = null;
const { leading = true, trailing = false } = options;
<p>return function throttled(...args) {
const now = Date.now();</p><pre class="brush:php;toolbar:false;">if (leading && now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
} else if (!leading && !timerId) {
timerId = setTimeout(() => {
fn.apply(this, args);
lastTime = Date.now();
timerId = null;
}, delay);
}
if (trailing && !timerId) {
timerId = setTimeout(() => {
fn.apply(this, args);
lastTime = Date.now();
timerId = null;
}, delay);
}}; }
⚠️ 注意:标准节流通常只选一种模式(leading 或 trailing),同时启用两者易导致重复执行。更稳妥的做法是分离逻辑或明确互斥。
简化健壮版:推荐日常使用
多数场景只需一种行为。以下为清晰、无歧义的 trailing-only 版本(滚动/拖拽常用),delay 可随时调整:
function throttle(fn, delay) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
}
};
}
<p>// 使用示例:每 500ms 最多执行一次
const handleResize = throttle(() => console.log('resized'), 500);
window.addEventListener('resize', handleResize);</p>
如需动态改频,可封装成工厂函数或暴露更新方法,例如:
const throttledFn = throttle(myHandler, 300); // 后续想改成 100ms?重新创建即可 const newThrottled = throttle(myHandler, 100);
进阶:支持运行时修改 delay(可选)
若真需运行中切换频率,可用闭包保存 delay 并提供 setter:
function throttleWithUpdate(fn, initialDelay) {
let delay = initialDelay;
let lastTime = 0;
<p>const throttled = function (...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
}
};</p><p>throttled.setDelay = (newDelay) => {
delay = Math.max(0, newDelay);
};</p><p>return throttled;
}</p><p>const t = throttleWithUpdate(() => console.log('run'), 200);
t(); // 立即执行
t.setDelay(1000); // 下次起按 1s 间隔</p>
这种设计适合配置中心驱动的场景,但多数前端交互无需如此复杂——重新绑定新节流函数更直观可靠。











