使用一堆setTimeouts或setInterval来刷新一堆对象是否更有效

时间:2012-07-07 17:16:36

标签: javascript node.js v8 spidermonkey

假设有一组Watcher需要定期刷新。它们每个可能具有不同的刷新间隔。在任何给定时刻可能有数百个Watcher个项目。任何Watcher的刷新时间可以从秒到几分钟或几小时。

哪个更好?

  • 为每个人使用单独的setTimeout

  • 使用每秒运行一次函数的setInterval。然后,函数会循环检查每个Watcher以查看是否需要刷新。

起初我假设setTimeout的本机代码实现比执行检查的JS函数更有效,但它实际上是如何实现setTimeout的问题,每个超时的开销是多少取每个刻度,以及超时数量的缩放程度。

我问这个节点应用程序,所以我所指的具体引擎是V8,但如果有人知道其他引擎的细节,那就太酷了。

1 个答案:

答案 0 :(得分:3)

无论如何实现setTimeout或setInterval,这都是一个非常有效的想法。如果您将来有N个事件安排在N个不同的时间,请创建一个对象数组,其中每个对象在事件到期时具有属性,并且该属性告诉您它是什么类型的事件(回调或某些事件)其他标识符)。最初按时间属性对该数组进行排序,以便下一次在事件的前面,最远的时间在最后。

然后,查看数组的前面,计算直到该事件的时间并在该持续时间内执行setTimeout()。当setTimeout()触发时,查看数组的开头并处理所有到达时间的事件。如果在处理事件之后,您需要安排它的下一次出现,那么计算将来应该触发的时间并从头到尾遍历数组,直到找到它之后的事件并在该事件之前插入此事件(以按排序顺序保持数组)。如果未找到,请将其插入末尾。处理完阵列前端的所有事件后,将增量时间计算到阵列前面的事件,并为该间隔发出新的setTimeout()

这是一些伪代码:

function orderedQueue() {
    this.list = [];
}

orderedQueue.prototype = {
    add: function(time, callback) {
        var item = {}, added = false;
        item.time = time;
        item.cb = callback;
        for (var i = this.list.length - 1; i >= 0; i--) {
            if (time > this.list[i].time) {
                // insert after the i item
                this.list.splice(i + 1, 0, item);
                added = true;
                break;
            }
        }
        // if no item was after this item, 
        // then put this on the front of the array
        if (!added) {
            this.list.unshift(item);
        }
    },
    addDelta(delta, callback) {
        var now = new Date().getTime();
        this.add(now + delta, callback);
    },
    waitNext: function() {
        // assumes this.list is properly sorted by time
        var now = new Date().getTime();
        var self = this;
        if (this.list.length > 0) {
            // set a timer for the first item in the list
            setTimeout(function() {
                self.process();
            }, this.list[0].time - now);
        }
    },
    process: function() {
        var now,item;
        // call all callbacks who's time has been reached
        while (this.list.length) {
            now = new Date().getTime();
            if (this.list[0].time <= now) {
                // remove front item from the list
                item = this.list.shift();
                // call the callback and pass it the queue
                item.cb(this);
            } else {
                break;
            }
        }
        // schedule the next item
        this.waitNext();
    }
}

而且,这里通常是你如何使用它:

var q = new orderedQueue();
// put initial events in the queue
q.addDelta(100, f1);
q.addDelta(1000, f2);
q.addDelta(5000, f3);
q.addDelta(10000, f4);
q.addDelta(200, f5);
q.addDelta(100, f1);
q.addDelta(500, f1);
// start processing of queue events
q.waitNext();