降低 Javascript 事件轮询的频率

发布于 2024-10-06 12:14:44 字数 171 浏览 0 评论 0原文

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

How do you lower the frequency of Javascript event polling? The events I'm concerned about are onResize and onScroll. These events may be triggered dozens of times per second when someone resizes their browser or scrolls down, respectively. I'd like these events to happen only once every 500 ms so I don't have to spend hours optimizing my event handlers and making sure they don't leak memory.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

北方的巷 2024-10-13 12:14:44
var resizeTimeout;

window.onresize = function() {
    if (resizeTimeout) {
        clearTimeout(resizeTimeout);
    }
    resizeTimeout = setTimeout(function() {
        // Do it!
    }, 500);

});

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

onscroll 版本非常相似:)

var resizeTimeout;

window.onresize = function() {
    if (resizeTimeout) {
        clearTimeout(resizeTimeout);
    }
    resizeTimeout = setTimeout(function() {
        // Do it!
    }, 500);

});

This will trigger the setTimeout() function ~500ms after the person has finished resizing.

The onscroll version is very similar :)

杀お生予夺 2024-10-13 12:14:44

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

You can't really control how frequently the event fires, you can do something like remember the time of first event firing, then on each consequent one you check if it's more than 500 ms from first one - if yes, you proceed with the event handler, otherwise you just exit the event hanlder

冬天旳寂寞 2024-10-13 12:14:44

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

At the beginning of your handler, check to see if 500ms have passed since the last one, and just return if not.

乄_柒ぐ汐 2024-10-13 12:14:44

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

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

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

You can't prevent these events from firing. They always do. What you want to do is stop listening immediately, then handle the event to avoid repetition. Then the entire handler is set up again after setTimeout. No more recursion happens unless somebody resizes the window. I use 5000ms here as it's easier to see it working in the console. You shouldn't see more than one spam in the FF console every 5 seconds even if you resize like a spaz.

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

Using logic to decide whether to do anything every time the handler fires is still technically firing a handler and an if statement + lookup. That can get heavy.

温馨耳语 2024-10-13 12:14:44

检查下划线 debounce 函数

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

例子:

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

check the underscore debounce function

Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving. For example: rendering a preview of a Markdown comment, recalculating a layout after the window has stopped being resized, and so on.

Example:

window.onscroll = _.debounce(
  function() {
      // do something
  }, 500, false
);
老旧海报 2024-10-13 12:14:44

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

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
    //...
}

我希望这会有所帮助。

I used to make it like on the accepted answer but the problem is, it only triggers after the timeout specified. I wanted a solution that handles the resize right away, the first time. Here is what I ended up doing.

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
    //...
}

I hope this will help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文