事件循环如何从不阻塞但队列中的消息已 运行 完成?

How is the event loop never blocking but messages in the queue are run to completion?

我正在了解 JavaScript 的 事件循环 on the MDN doc。它提到队列中的一条消息是 运行 完成,但最后却说事件循环从不阻塞。我真的不明白这一点。这不是自相矛盾吗?请帮助我了解它们之间的区别。

"Run-to-completion"

Each message is processed completely before any other message is processed. This offers some nice properties when reasoning about your program, including the fact that whenever a function runs, it cannot be pre-empted and will run entirely before any other code runs (and can modify data the function manipulates). This differs from C, for instance, where if a function runs in a thread, it may be stopped at any point by the runtime system to run some other code in another thread.

A downside of this model is that if a message takes too long to complete, the web application is unable to process user interactions like click or scroll. The browser mitigates this with the "a script is taking too long to run" dialog. A good practice to follow is to make message processing short and if possible cut down one message into several messages.

Never blocking

A very interesting property of the event loop model is that JavaScript, unlike a lot of other languages, never blocks. Handling I/O is typically performed via events and callbacks, so when the application is waiting for an IndexedDB query to return or an XHR request to return, it can still process other things like user input.

你是对的,这两个引文相互矛盾。

在事件循环中,所有消息都是运行-to-completion,因为它写在第一篇文章中,因此它们do阻塞事件循环而他们执行。

这就是为什么 timer2timer1 中的循环完成之前不会执行的原因,在此示例中:

console.log('start');

setTimeout(() => {
  const startTime = Date.now()
  while(Date.now() - startTime < 3000);
  console.log('timer1 end');
}, 0)
setTimeout(() =>  console.log('timer2'), 0);

/*
start
-- three seconds later --
timer1 end
timer2
*/

“从不阻塞”的文字应该意味着,与许多语言不同,大多数需要很长时间(或轮询速度较慢)的 API 被设计为不会长时间阻塞事件循环 time,而是指示 JS 运行time 在不阻塞的情况下在后台线程中处理任务 JavaScript,并在准备就绪时将结果传回给 JS。

对此更准确的描述是“虽然事件循环可以被长运行宁代码阻塞,但大多数 JS API 旨在避免这样做”。