事件循环什么时候开始?

When does the event loop turn?

我对 浏览器 中的事件循环何时旋转感到有点困惑。

问题是:

假设我们有一个网页,在 前端 我们有 JavaScript 代码来安排任务并等待承诺(这是一个微任务)。 promise 的执行被认为是在与任务相同的事件循环轮次中发生,还是在不同的迭代中发生?

我目前假设它们都发生在同一次迭代中。因为如果不这样打赌,在微任务在任务执行过程中执行的情况下,这将意味着该任务将需要多次循环迭代才能完全完成。这对我来说似乎是有线的。也可以说可能在每个任务之后发生的更新渲染部分发生在同一个循环中是否正确?

提前致谢!

-------------------------------------------- --------------------------------------

我知道我应该添加评论,但它会很长,而且我还需要编写代码,所以我正在编辑问题并在这里寻求澄清。

@T.J。 Crowder 非常感谢您的时间和详细的解释!

我确实误读了this great article中的"microtasks are processed after callbacks (as long as no other JavaScript is mid-execution)",有点糊涂了。

我也有关于 4ms setTimout 的问题,我找不到相关信息,所以也感谢您提供该信息。

不过还有最后一件事...如果我们要标记示例代码之间的循环节拍,我们会将它们放在哪里(假设 console.logs 不存在)?

假设我们有一个名为 exampleCode 的函数,其主体如下:

setTimeout(setTimeoutCallback, 0);
Promise.resolve().then(promiseCallback);

对于上面的代码,我的猜测是...

就在执行 exampleCode(宏)任务之前:

或者在 Promise.then 微任务调度 promiseCallback 执行 之间是否有额外的循环滴答?

再次感谢您!

Does a task and the pending microtasks, happen in the same loop iteration/turn/tick?

任务发生,然后当它结束时,它安排的任何未决微任务都是 运行。

Which are the actual conditions that need to be met in order for the loop to turn?

不清楚你的意思。根据 jobsjob queue(这是 ECMAScript 规范的术语)来思考可能更容易:如果有待处理的作业并且为该队列提供服务的线程没有做其他事情,它接手工作并运行完成它。

Are these conditions the same in node.js event loop?

足够接近了,是的。

Let's say we have a webpage and in the front end we have JavaScript code that schedules a task and waits for a promise (which is a microtask). Is the execution of the promise considered to happen in the same turn of the event loop as the task, or in different iterations?

在浏览器(和 Node)中,它发生在任务完成之后,当任务的微任务(如果有的话)是 运行 时,在下一个排队的 task/job 被拾取之前。

例如:

// This code is run in a task/job

console.log("Scheduling (macro)task/job");
setTimeout(() => {
    console.log("timeout callback ran");
}, 0);

console.log("Scheduling microtask/job");
Promise.resolve().then(() => {
    console.log("promise then callback ran");
});

console.log("main task complete");

在兼容的浏览器(和 Node)上,将输出:

Scheduling (macro)task/job
Scheduling microtask/job
main task complete
promise then callback ran
timeout callback ran

...因为微任务 运行 当主任务完成时,在下一个宏任务 运行.

之前

(请注意,如果不是 嵌套 超时,setTimeout(..., 0) 确实会在兼容的浏览器上立即将计时器安排到 运行;more here 。你会看到有人说没有"setTimeout 0",但那是过时的信息。如果定时器的嵌套级别> 5,它只会被钳制到4ms。)

更多探索:


回复edit/comment中的代码和问题:

setTimeout(setTimeoutCallback, 0);
Promise.resolve().then(promiseCallback);

你的猜测看起来不错。以下是我对它的描述:

  1. 将任务安排到运行那个脚本
  2. (线程下次空闲时)
    1. 接下一个任务(来自上面的#1)
    2. 运行那个任务:
      1. 创建定时器回调任务
        • 并行,时间到了就把任务排队
      2. 为 promise then 回调
      3. 排队微任务
      4. 任务结束
    3. 微任务检查
      • 运行 then 回调
  3. (线程下次空闲时)
    1. 接下一个任务(定时器回调的任务)
    2. 运行任务
    3. 任务结束
    4. 微任务检查(none 在这种情况下执行)

处理模型文本明确指出任务在微任务检查之前结束,但我认为这无法以任何实际方式观察到。