13

我在使用 jQuery 插件tablesorter时遇到问题,我不能两次调用触发器。

例如,这将不起作用:

this._$table.trigger('update');
this._$table.trigger('sorton', [[[1,1]]]);

但这有效:

this._$table.trigger('update');
setTimeout($.proxy(function() {
    this._$table.trigger('sorton', [[[1,1]]]);
}, this), 1);

然后我看到问题出在触发器“更新”中,它使用正文调用方法:

function () {
    var me = this;
    setTimeout(function () {
        // rebuild parsers.
        me.config.parsers = buildParserCache(
        me, $headers);
        // rebuild the cache map
        cache = buildCache(me);
    }, 1);
}

为什么 tablesorter 开发人员使用setTimeout一毫秒?

4

3 回答 3

18

简短的回答:函数执行排队

这是对您问题的简短回答。setTimeout0 或 1 毫秒用于函数执行队列。继续阅读以了解原因和方式。

Javascript具有单线程执行

Javascript引擎是一个单线程进程。因此,每当开发人员想要推迟某些函数执行以在当前刚刚执行的函数之后立即执行时,asetTimeout被用于实际排队下一个函数......它与事件没有任何直接关系,尽管函数可能是事件处理程序。此等式中的唯一事件是 setTimeout 创建的超时事件。

这是两个函数的示例,其中第一个函数在其执行期间将第二个函数排入队列,以便在其之后立即执行。

function first()
{
    // does whatever it needs to

    // something else needs to be executed right afterwards
    setTimeout(second, 1);

    // do some final processing and exit
    return;
}

function second()
{
    // whatever needs to be done
}

因此,对于 javascript 引擎线程,执行队列如下所示:

first()
second()

请注意,这与函数调用堆栈无关

为什么是 1 毫秒?

1ms 是一个非常短的时间,(几乎)可以确保您的第二个函数将在您的第一个函数返回后立即执行。您有时甚至会看到0ms实际在第一个函数返回后立即执行它。

另一方面,如果使用更长的时间,即 100 毫秒,这可能会导致同时执行不同的函数,这可能会对整个 UI 过程产生不良影响。

为什么首先要进行函数排队?

现在的浏览器通过观察长时间运行的功能来阻止客户端功能挂起当前浏览器会话。如果特定函数运行时间足够长,浏览器 Javascript 执行引擎将暂停它并询问用户是要终止它(杀死它)还是等待它完成。

当您实际上确实具有长时间运行的功能时,这通常是不希望的效果。例如,假设您有一个函数必须在处理过程中循环处理大量项目。您绝对不希望用户终止进程,因为循环需要执行。

在这种情况下有什么解决方案?在这种情况下,您宁愿使用循环(排队)函数,然后将函数调用排队以处理每个项目,而不是使用带有循环的单个函数并执行它。这只是这种功能的一个外部骨架。

function queueItems(items) {
    for(var i = 0; i < items.length, i++)
    {
        setTimeout((function(item) {
            return function() {
                processItem(item);
            };
        })(items[i]), 0);
    }
}

function processItem(item) {
    // process individual item
}

这样你就可以防止你的函数运行太久,并且在每个执行的函数控制之后返回到 Javascript 引擎重置它的函数挂起计时器。但是请注意,当您的函数正在执行时,您的 UI 可能会无响应或最多是不可预测的。最好在函数之间留出一些时间空间来排队,以便 UI 在需要时保持响应。

于 2012-08-21T09:27:13.787 回答
17

这是一个古老的黑客。如果一个事件需要在另一个事件之后触发,您可以使用setTimeout1ms 来确保该事件在另一个事件之后触发。

于 2012-08-21T09:26:43.773 回答
1

我认为由于trigger('update')内部有一个setTimeout,只有通过设置另一个setTimeout才能实现所需的语句执行顺序。如果您不调用它'sorton'setTimeout它将在之前执行'update'

另一方面,我猜想'update'用于setTimeout防止“更新”成为阻塞功能,因为它可能需要很长时间才能执行。

于 2012-08-21T09:25:41.397 回答