【问题标题】:Lower the frequency of Javascript event polling降低 Javascript 事件轮询的频率
【发布时间】:2010-12-07 02:04:30
【问题描述】:

如何降低 Javascript 事件轮询的频率?我关心的事件是onResizeonScroll。当有人调整浏览器大小或向下滚动时,这些事件可能每秒触发数十次。我希望这些事件每 500 毫秒发生一次,这样我就不必花费数小时优化我的事件处理程序并确保它们不会泄漏内存。

【问题讨论】:

    标签: javascript event-handling dom-events onscroll onresize


    【解决方案1】:
    var resizeTimeout;
    
    window.onresize = function() {
        if (resizeTimeout) {
            clearTimeout(resizeTimeout);
        }
        resizeTimeout = setTimeout(function() {
            // Do it!
        }, 500);
    
    });
    

    这将在人完成调整大小约 500 毫秒后触发 setTimeout() 函数。

    onscroll 版本非常相似:)

    【讨论】:

    • 这个不会每 500 毫秒触发一次,它只会在您停止/暂停调整大小后 500 毫秒触发
    • +1 击败了我。记得检查resizeTimeout,因为第一次是undefined
    • @Andrey 是的,我知道,我提到过。它可能仍然适用于 OP。
    • @alex,在调整大小暂停/停止后调用处理程序与“实时”调用处理程序不同,但速度比浏览器触发事件​​的速度要慢。
    【解决方案2】:

    您无法真正控制事件触发的频率,您可以执行一些操作,例如记住第一个事件触发的时间,然后在每个后续事件上检查它是否比第一个事件超过 500 毫秒 - 如果是,您继续使用事件处理程序,否则您只需退出事件处理程序

    【讨论】:

    • +1 对于这个答案,这可能是 OP 想要的。但是,您需要一些额外的逻辑来处理最后的调整大小事件。
    • 我认为计时器解决方案会处理最后一次调整大小事件,所以真正的解决方案是两者的某种组合
    【解决方案3】:

    在您的处理程序开始时,检查自上一个处理程序以来是否经过了 500 毫秒,如果没有则返回。

    【讨论】:

      【解决方案4】:

      您无法阻止这些事件触发。他们总是这样做。您要做的是立即停止收听,然后处理事件以避免重复。然后在 setTimeout 之后再次设置整个处理程序。除非有人调整窗口大小,否则不会再发生递归。我在这里使用 5000 毫秒,因为更容易看到它在控制台中工作。即使您像垃圾邮件一样调整大小,您也不应该每 5 秒在 FF 控制台中看到超过一个垃圾邮件。

      (function staggerListen(){
        window.onresize = function(){
          window.onresize = false;
          console.log('spam');
          setTimeout(staggerListen,5000);
        };
      })()
      

      使用逻辑来决定每次处理程序触发时是否执行任何操作在技术上仍然是触发处理程序和 if 语句 + 查找。这可能会变得很重。

      【讨论】:

      • 哇。我不确定动态添加/删除侦听器回调的开销是多少,但无论如何,+1 是棘手的。 :)
      【解决方案5】:

      检查下划线debounce函数

      创建并返回传递函数的一个新的去抖动版本,该版本将推迟其执行,直到自上次调用它起等待毫秒过去后。对于实现仅在输入停止到达后才应发生的行为很有用。例如:渲染 Markdown 注释的预览、窗口停止调整大小后重新计算布局等等。

      例子:

      window.onscroll = _.debounce(
        function() {
            // do something
        }, 500, false
      );
      

      【讨论】:

        【解决方案6】:

        我曾经让它像接受的答案一样,但问题是,它只在指定的超时后触发。我想要一个第一次立即处理调整大小的解决方案。这就是我最终要做的。

        var _resize_is_busy = false;
        var _resize_scheduled = false;
        var _resize_precision = 100;
        
        // This register for window resize events. No need to change anything.
        $(window).resize(function () {
        
            if (!_resize_is_busy) {
        
                // call the scheduler who will do the work and set a timer to
                // check of other resizes occured within a certain period of time
        
                _resize_scheduler();
            }
            else {
        
                // the resizer is busy, i.e. a resize have been handled a little
                // time ago and then the scheduler is waiting some time before 
                // handling any other resize. This flag tells the scheduler that
                // a resize event have been receive while he was sleeping.
        
                _resize_scheduled = true;
            }
        });
        
        // This is the scheduler. No need to change anything.
        var _resize_scheduler = function () {
        
            _resize_is_busy = true;
            _resize_scheduled = false;
        
            setTimeout(function () {
        
                _resize_is_busy = false;
        
                if (_resize_scheduled) 
                    _handle_resize();
        
            }, _resize_precision);
        
            _handle_resize();
        }
        
        var _handle_resize = function () {
        
            console.log('DOING ACTUAL RESIZE');
        
            // do the work here
            //...
        }
        

        我希望这会有所帮助。

        【讨论】:

          猜你喜欢
          • 2014-02-06
          • 2017-07-17
          • 1970-01-01
          • 1970-01-01
          • 2019-11-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多