11

这些天,我阅读了一些关于setTimeout和的文件setInterval。我了解到 Javascript 是一个单线程,每次只会执行一段代码。同时,如果有事件发生,它会被推入事件队列并阻塞到合适的时间。我想知道,当许多事件被阻塞等待同时执行时。这些事件是否有不同的优先级,所以高优先级的事件将在低优先级之前执行。或者只是一个先进先出队列。

setTimeout(fn1, 10);
$(document).click(fn2); //will be called at 6ms;
$.ajax({ajaxSuccess(fn3); //async request,it uses 7ms;})

 for () {
    //will run 18ms;
};

在上面的代码中,setTimeout fn1 将在 10 ms 发生,click 事件处理程序 fn2 将在 6ms 发生,ajax 回调 fn3 将在 7ms 发生,但这三个函数都会被阻塞,直到 for 循环完成。在 18ms 时,for 循环结束,那么这些函数将按什么顺序被调用。(fn1,fn2,fn3) 或 (fn2,fn3,fn1)

4

3 回答 3

13

为主 JavaScript 线程安排的工作是 FIFO 处理的。这包括来自各种异步任务的回调,例如setTimeoutajax 完成和事件处理程序。唯一的例外是,在主要流行环境(浏览器和 Node)中,本机的解析回调会Promise跳队列(更准确地说,进入不同的更高优先级队列),有关详细信息,请参阅我的答案

但抛开原生承诺解析回调:

但是所有三个函数都将被阻塞,直到 for 循环完成。在 18ms 时,for循环结束,那么这些函数将按什么顺序被调用。(fn1,fn2,fn3) 或 (fn2,fn3,fn1)

您给出的时间setTimeout是近似的,因为到了该时间时,JavaScript UI 线程可能正忙于做其他事情(如您所知);(新的)规范还需要最短时间,但实施的程度因实施而异。同样,您不能保证点击事件将在 6ms 排队,或者 ajax 完成将恰好在 7ms 发生。

如果该代码启动,并且浏览器精确地执行了 10 毫秒,并且click事件恰好在 6 毫秒内排队,并且ajax 请求恰好在 7 毫秒完成,那么顺序将是:(fn2处理click程序),fn3(ajax 完成),fn1setTimeout),因为这是他们排队的顺序。

但请注意,这些时间非常紧迫。在实践中,我希望回调排队的顺序实际上是随机的,因为时间click会有所不同,时间ajax会有所不同,等等。

我认为这是一个更好的例子:

var start = +new Date();

// Queue a timed callback after 20ms
setTimeout(function() {
    display("20ms callback");
}, 20);

// Queue a timed callback after 30ms
setTimeout(function() {
    display("30ms callback");
}, 30);

// Queue a timed callback after 10ms
setTimeout(function() {
    display("10ms callback");
}, 10);

// Busy-wait 40ms
display("Start of busy-wait");
var stop = +new Date() + 40;
while (+new Date() < stop) {
    // Busy-wait
}
display("End of busy-wait");

function display(msg) {
    var p = document.createElement('p');
    var elapsed = String(+new Date() - start);
    p.innerHTML = "+" + "00000".substr(elapsed.length - 5) + elapsed + ": " + msg;
    document.body.appendChild(p);
}

输出的顺序将是两个循环消息,然后是 10ms 回调、20ms 回调和 30ms 回调,因为这是回调排队等待主 JavaScript 线程服务的顺序。例如:

+00001:忙等待开始
+00041:忙等待结束
+00043: 10ms 回调
+00044: 20ms 回调
+00044: 30ms 回调

...其中+数字表示自脚本启动以来的毫秒数。

于 2013-11-02T16:18:44.303 回答
10

javascript事件队列有优先权吗?

有点。事件循环实际上是由一个或多个事件队列组成的。在每个队列中,事件按 FIFO 顺序处理。

由浏览器决定拥有多少个队列以及给予它们什么形式的优先级。没有针对单个事件队列或将事件发送到特定队列的 Javascript 接口。

https://www.w3.org/TR/2014/REC-html5-20141028/webappapis.html#event-loops

每个任务都被定义为来自特定的任务源。必须始终添加来自一个特定任务源并发往特定事件循环的所有任务(例如,由 Document 的计时器生成的回调、为鼠标在该 Document 上移动而触发的事件、排队等待该 Document 解析器的任务)到同一个任务队列,但是来自不同任务源的任务可能被放在不同的任务队列中。

例如,用户代理可以有一个用于鼠标和按键事件(用户交互任务源)的任务队列,另一个用于其他所有事件。然后,用户代理可以在四分之三的时间内将键盘和鼠标事件优先于其他任务,保持界面响应但不会饿死其他任务队列,并且永远不会无序地处理来自任何一个任务源的事件。

于 2014-02-04T16:59:32.677 回答
2

先进先出。真的没有什么好说的了。你没有时间安排它。

当您查看可能同时发生的多个超时操作时,这可能会有点痛苦。也就是说,如果您使用的是异步行为,则不应依赖于它们的调度方式。

于 2013-11-02T15:17:00.493 回答