1098 字
5 分钟
JavaScript 节流
.png)
题目描述
实现 JavaScript 节流函数,要求:
- 固定时间间隔内只执行一次函数
- 支持立即执行选项(首次触发立即执行)
- 支持尾部执行选项(最后一次触发后执行)
- 支持取消功能(在等待期间取消执行)
- 正确处理函数参数和 this 绑定
要求完整实现节流逻辑,并通过测试用例验证。
解题思路
- 时间戳控制:记录上次执行时间判断是否满足间隔
- 计时器管理:使用 setTimeout 实现尾部执行
- 立即执行选项:首次触发立即执行函数
- 尾部执行选项:最后一次触发后执行函数
- 取消机制:提供取消执行的方法
- 参数传递:保存函数参数并正确传递
关键洞察
- 频率控制本质:通过时间间隔限制函数执行次数
- 双模式互补:时间戳模式保证立即响应,计时器模式保证最终执行
- 执行时机分离:头部执行保证即时性,尾部执行保证完整性
- 状态管理机制:闭包保存执行状态和时间戳
- 参数保存机制:闭包保存参数确保最新值
- 上下文绑定:使用 apply 确保 this 正确
代码流程
flowchart TD A[调用节流函数] --> B{是否首次执行?} B -->|是且立即执行| C[立即执行函数] B -->|否| D{是否在间隔内} D -->|是| E[设置尾部执行] D -->|否| F[立即执行] G[取消操作] --> H[清除计时器]
代码实现
// 基础防抖const basicDebounce = debounce(() => { console.log('Resize event handled');}, 250);
window.addEventListener('resize', basicDebounce);
// 立即执行防抖const searchDebounce = debounce((query) => { console.log(`Searching for: ${query}`);}, 500, {leading: true});
searchInput.addEventListener('input', (e) => { searchDebounce(e.target.value);});
// 取消示例const cancelableDebounce = debounce(() => { console.log('This will not run if canceled');}, 1000);
cancelableDebounce();setTimeout(cancelableDebounce.cancel, 500); // 取消执行
// Promise支持function throttle(func, wait = 300, options = {}) { let timerId = null; let lastArgs = null; let lastThis = null; let lastTime = 0;
// 选项默认值处理 const leading = 'leading' in options ? !!options.leading : true; const trailing = 'trailing' in options ? !!options.trailing : true;
// 执行目标函数 function invokeFunc(time) { lastTime = time; return func.apply(lastThis, lastArgs); }
// 主函数 function throttled(...args) { const now = Date.now(); lastArgs = args; lastThis = this;
// 计算剩余等待时间 const remaining = wait - (now - lastTime);
// 首次执行判断 if (remaining <= 0 || remaining > wait) { // 清除尾部计时器 if (timerId) { clearTimeout(timerId); timerId = null; }
// 满足间隔要求,立即执行 return invokeFunc(now); }
// 设置尾部执行 if (trailing && !timerId) { timerId = setTimeout(() => { timerId = null; if (trailing && lastArgs) { return invokeFunc(Date.now()); } }, remaining); } }
// 取消方法 throttled.cancel = function() { clearTimeout(timerId); timerId = null; lastArgs = null; lastThis = null; lastTime = 0; };
// 立即执行当前值 throttled.flush = function() { if (timerId) { clearTimeout(timerId); timerId = null; return invokeFunc(Date.now()); } };
return throttled;}const promiseDebounce = debounce((value) => { return Promise.resolve(`Processed: ${value}`);}, 300);
promiseDebounce('data').then(console.log); // 输出: Processed: data
使用示例
// 基础节流const basicThrottle = throttle(() => { console.log('Scroll event handled');}, 250);
window.addEventListener('scroll', basicThrottle);
// 立即执行节流const leadingThrottle = throttle(() => { console.log('Immediate execution');}, 500, {leading: true});
button.addEventListener('click', leadingThrottle);
// 尾部执行节流const trailingThrottle = throttle(() => { console.log('Trailing execution');}, 500, {trailing: true});
input.addEventListener('input', trailingThrottle);
// 取消示例const cancelableThrottle = throttle(() => { console.log('This will not run if canceled');}, 1000);
cancelableThrottle();setTimeout(cancelableThrottle.cancel, 500); // 取消执行
业务场景
- 滚动事件:页面滚动时监听位置变化(如导航栏显示/隐藏)
- 鼠标移动:拖拽操作时的元素位置更新
- 实时预览:表单输入时实时预览内容(如Markdown编辑器)
- 游戏控制:键盘事件处理(如角色移动控制)
- 性能监控:定期采集性能指标数据
- 动画效果:scroll-linked动画控制(如视差滚动)
性能优势:
- 保证高频事件的核心功能稳定执行
- 避免过度渲染导致的页面卡顿
- 减少不必要的计算资源消耗
- 平衡用户体验与性能消耗
- 防止接口频繁调用导致服务器压力
相似题目
- 防抖(Debounce)实现(简单) 核心:延迟执行直到事件停止触发
- 动画帧节流(中等) 核心:requestAnimationFrame 实现动画控制
- 滚动位置监听优化(中等) 核心:IntersectionObserver + 节流
- 请求节流控制(困难) 核心:限制接口调用频率(如API限流)
- 鼠标跟随效果优化(中等) 核心:mousemove事件节流实现平滑跟随