You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无事件监听器时实现函数调用限流(节流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()时没有传递任何参数,同时逻辑本身也不符合你的需求:

  1. 节流函数依赖storedEvent记录后续调用,但你调用时无参数,导致storedEvent始终是undefined,延迟结束后无法触发后续执行
  2. 当前逻辑更偏向防抖(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:26:14