无事件监听器时实现函数调用限流(节流throttle)问题排查
问题:URL变更回调中的节流函数失效问题
我有一个包含大量视频的无限滚动长页面,需要刷新固定位置的广告。每次滚动到新视频时URL会更新,触发回调函数调用广告刷新方法。希望对该刷新函数的调用做限流,避免用户快速滚动时刷新过于频繁。我在按钮点击事件监听器的测试场景中成功实现了节流功能,但在无事件监听器的URL变更回调场景中无法正常工作。以下是基础代码,需对refreshFirstSlot函数的调用进行限流,请问我的代码哪里出现了问题?
// Function which refreshes the first slot var refreshFirstSlot = function () { googletag.cmd.push(function () { googletag.pubads().refresh([adSlot1]); }); }; // UrlUpdate is called each time the URL updates UrlUpdate = function (url, type) { refreshFirstSlot(); }; // throttle code const throttle = (callback, delay) => { let throttleTimeout = null; let storedEvent = null; const throttledEventHandler = (event) => { storedEvent = event; const shouldHandleEvent = !throttleTimeout; if (shouldHandleEvent) { callback(storedEvent); storedEvent = null; throttleTimeout = setTimeout(() => { throttleTimeout = null; if (storedEvent) { throttledEventHandler(storedEvent); } }, delay); } }; return throttledEventHandler; }; // adding the refresh call var returnedFunction = throttle(function () { refreshFirstSlot(); }, 5000); // final call UrlUpdate = function (url, type) { returnedFunction(); };
问题分析
你的节流函数是为带event参数的事件场景设计的,但在URL变更回调中调用returnedFunction()时没有传递任何参数,同时逻辑本身也不符合你的需求:
- 节流函数依赖
storedEvent记录后续调用,但你调用时无参数,导致storedEvent始终是undefined,延迟结束后无法触发后续执行 - 当前逻辑更偏向防抖(debounce)的尾随触发,而非真正的节流(固定间隔执行),频繁调用时后续的URL变更会被完全忽略,达不到「每5秒最多刷新一次」的效果
修正后的代码
调整节流函数为无参数场景适配的版本,实现「固定时间间隔内只执行一次」的核心逻辑:
// 广告刷新函数 var refreshFirstSlot = function () { googletag.cmd.push(function () { googletag.pubads().refresh([adSlot1]); }); }; // 适配无参数场景的节流函数:固定间隔执行,支持可选尾随触发 const throttle = (callback, delay) => { let lastExecTime = 0; let timeoutId = null; return function () { const now = Date.now(); // 距离上次执行超过延迟时间,立即执行 if (now - lastExecTime >= delay) { clearTimeout(timeoutId); timeoutId = null; lastExecTime = now; callback(); } else if (!timeoutId) { // 可选:如果用户停止滚动,确保最后一次URL变更能触发刷新 timeoutId = setTimeout(() => { lastExecTime = Date.now(); timeoutId = null; callback(); }, delay - (now - lastExecTime)); } }; }; // 创建节流后的刷新函数,5秒内最多执行一次 var throttledRefresh = throttle(refreshFirstSlot, 5000); // URL变更回调:调用节流后的函数 UrlUpdate = function (url, type) { throttledRefresh(); };
关键修正点
- 移除了对
event参数的依赖,适配无参数调用场景 - 用
lastExecTime记录上次执行时间,严格保证每5秒至少执行一次 - 可选的尾随执行逻辑:如果用户快速滚动后停止,最后一次URL变更会在冷却期结束后触发刷新(不需要的话可删除
else if (!timeoutId)代码块)
内容的提问来源于stack exchange,提问作者Soopablogga
相关产品推荐
相关产品推荐

