提问者:小点点

美元(文件)。ready()在主线程中执行,还是异步执行?


我正在使用$(文档)中的图形可视化库。准备好了(),它似乎阻止了用户界面。我期望$(文档).就绪()在一个单独的线程中执行。

有人知道细节吗?也许我应该使用setTimeout异步运行代码?

编辑:

术语“异步”和“独立线程”在JavaScript中具有误导性。我不是JavaScript专家,也找不到更准确的术语。请参阅答案以进行澄清。


共3个答案

匿名用户

除了Web Worker(不能直接访问DOM)之外,JavaScript在一个线程中运行。$(文档)。准备好了()是异步的,因为你传递给它的回调可能会立即触发,或者稍后某个时候DOM已经加载,但是当它的回调实际运行时,它是JS运行时唯一正在处理的事情。

例如,一个长时间运行的for循环将阻塞UI线程,而不管它是否在就绪回调、事件处理程序、异步XHR的成功回调等中。防止它阻塞线程的唯一方法是通过使用setTimeout调度稍后的块,将其拆分为多个循环。

匿名用户

在JavaScript中没有单独的线程。所有JavaScript都在一个线程中执行;UI更新在同一个线程中执行。如果你的JavaScript很忙,UI更新就不会发生。“异步”在这里有点误导;它意味着函数的执行将被推迟(但仍然在一个线程中)。

基本上,浏览器有一个执行队列。所有事件处理程序在触发时都放入执行队列;超时函数也是如此。当任何没有调用方的函数退出时,将执行队列中的下一个函数。UI更新也在同一队列中。

因此,当您执行$(文档)时。ready(fn),它(简单地说,jQuery使它有点复杂,尤其是对于较旧的浏览器)将附加一个处理程序。当加载所有内容时,浏览器将触发此处理程序,从而将其放入执行队列。轮到它时,它会执行;它执行的任何UI更新都将在处理程序退出时绘制。

--

*)单线程规则有一个例外:web工作者。每个web工作者都在自己的线程中运行,但他们的能力非常有限;基本上,只进行计算(他们根本无法访问UI)。

匿名用户

异步并不意味着多线程。Javascript是基于事件的,当发生某些事情(事件发生)时将调用函数。事件侦听函数不是在单独的线程上执行的,它只是计划稍后执行。

但是有一种古老的技术可以在不支持浏览器的情况下模拟多线程。它将一个完整的任务分解为延迟的小任务。

例如,您编写了以下内容,这将导致阻塞:

for (var i = 0; i < 10000000; i++) {
    // do something very slow
}

将它转到这个位置,它将并行执行,几乎像多线程一样。

(function step(i) {
    if (i < 10000000) {
        // do something very slow
        setTimeout(function() {step(i + 1)}, 1);
    }
})(0);

编辑:我刚刚意识到这会导致内存问题,因为在每个步骤中,我们都引用了前一个步骤,使得GC无法清理内存。要克服这个问题,请将i从参数中去掉,然后像这样更改它(我用一个函数包装整个过程,这样i就不会在外部错误地更改):

(function() {
    var i = 0;
    (function step() {
        if (i < 10000000) {
            // do something very slow
            i++;
            setTimeout(step, 1);
        }
    })();
})();