DOMContentLoaded 事件和任务队列
我听说事件循环处理模型中有三个队列有任务。
- MacroTaskQueue :该队列具有 setTimeout、setInterval 等回调函数
- MicroTaskQueue :该队列具有 Promise、mutationOberver 等回调函数
- AnimationFrameQueue :该队列具有 requestAnimationFrame 回调函数。
所以,我想知道
- 谁触发了 DOMContentLoaded 事件?
- DOMContentLoaded 的回调函数在哪里排队? MacroTaskQueue 还是 MicroTaskQueue?
- 最后,
var a = 10;
console.log(a);
setTimeout(function b() { console.log('im b'); }, 1000);
在这段代码中,
var a = 10;
console.log(a);
这段代码是否也在 MacroTaskQueue 或 MicroTaskQueue 中排队?
或者只有 b
在(分钟)1000ms 后在 MacroTaskQueue 中排队?
我在黑洞里。请帮助我:D
I heard that there are three queues which have tasks in Event Loop Processing Model.
- MacroTaskQueue : this queue have callback functions of setTimeout, setInterval ..etc
- MicroTaskQueue : this queue have callback functions of promise, mutationOberver ..etc
- AnimationFrameQueue : this queue have callback functions of requestAnimationFrame.
So, what i'm wondering is that
- Who fires DOMContentLoaded event ?
- Where the callback function of DOMContentLoaded is queued ? MacroTaskQueue or MicroTaskQueue?
- finally,
var a = 10;
console.log(a);
setTimeout(function b() { console.log('im b'); }, 1000);
in this code,
var a = 10;
console.log(a);
is this code also queued in MacroTaskQueue or MicroTaskQueue ?
or only the b
is queued in MacroTaskQueue after (min) 1000ms ?
Im in black hole. Help me please :D
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您所谓的“MacroTaskQueue”实际上是由几个 任务队列< /a>,其中 任务正在排队。 (请注意,规范仅使用多个任务源,实际上可能有一个任务队列)。在 事件循环的开头处理时,浏览器将从哪个任务队列中选择要执行的下一个“主”任务。重要的是要理解这些任务很可能根本不意味着任何 JavaScript 执行,JS 只是浏览器所做的一小部分。
在单个事件循环迭代期间,微任务队列将被访问和清空多次。例如,每次 JS 调用堆栈有已清空(即几乎每次 JS 回调执行后),如果还不够,则 事件循环处理模型。
虽然与队列类似,但动画帧回调实际上存储在有序映射中,而不是本身存储在队列中,这允许从这些回调之一“排队”新回调,而不会立即将其出队。更重要的是,许多其他回调也同时执行 时间,例如滚动事件、调整大小事件、Web 动画步骤+事件、ResizeObserver 回调等。但是这个“更新渲染”步骤仅偶尔发生一次,通常以显示器刷新率发生。
但是,这并没有对 DOMContentLoaded 说太多。
此事件作为文档解析步骤的一部分被触发,在 "结束” 部分。浏览器必须首先在 DOM 操作任务源上排队一个任务。该任务最终将被浏览器选择,作为事件循环第一步的一部分。一旦执行该任务的步骤,该事件将被触发并分派到文档上。这只是浏览器调度事件算法的一部分< em>调用和内部调用直到调用我们监听器的回调。
请注意,这个文档解析步骤本身作为一项任务非常有趣,因为这是最明显的地方,您将在“主”任务中交错有多个微任务检查点(例如在每个
回调函数没有排队,它概念上存储在 EventTarget 的 事件监听器列表中。事实上,它存储在内存中,因为这里的 EventTarget 是一个 DOM 对象(文档),它可能附加到这个 DOM 对象,尽管这是一个实现细节,规范没有什么可说的,因为这对我们的 web 来说是透明的-开发人员。
我希望你现在能更好地理解,两者都不是。任务队列和微任务队列只存储任务和微任务,不存储回调。回调存储在其他地方,具体取决于它们的回调类型(例如,计时器和事件存储在不同的“概念”位置),然后某些任务或微任务的步骤将调用它们。
这取决于该脚本是从哪里解析的。如果它内联在经典的
标记中,那么这将是我们已经讨论过的特殊解析任务。如果它来自
,那么它将成为从 获取经典脚本,但它也可以是微任务的一部分,例如,如果在
await< 之后/代码>在模块脚本中,或者如果您愿意,您甚至可以强制它:
理论上甚至是可能的按规范微任务变成了“宏”任务,尽管显然没有浏览器再实现这一点。
综上所述,虽然我个人觉得所有这些东西都很有趣,但作为一名网络开发人员,你不应该在这方面阻止自己。
What you call the "MacroTaskQueue" is actually made of several task-queues, where tasks are being queued. (Note that the specs only use multiple task-sources, there could actually be a single task-queue). At the beginning of the event-loop processing, the browser will choose from which task queue it will pick the next "main" task to execute. It's important to understand that these tasks may very well not imply any JavaScript execution at all, JS is only a small part of what a browser does.
The microtask-queue will be visited and emptied several times during a single event-loop iteration. For instance every time that the JS call stack has been emptied (i.e after almost every JS callback execution) and if it wasn't enough there are fixed "Perform a microtask checkpoint" points in the event-loop processing model.
While similar to a queue, the animation frame callbacks are actually stored in an ordered map, not in a queue per se, this allows to "queue" new callbacks from one of these callbacks without it being dequeued immediately after. More importantly, a lot of other callbacks are also executed at the same time, e.g the scroll events, resize events, Web animation steps + events, ResizeObserver callbacks, etc. But this "update the rendering" step happens only once in a while, generally at the monitor refresh rate.
But, that's not saying much about DOMContentLoaded.
This event is fired as part of the Document parsing steps, in the "the end" section. The browser has to first queue a task on the DOM manipulation task-source. This task will then eventually get selected by the browser as part of the first step of the event-loop. And once this task's steps will be executed, the event will be fired and dispatched on the Document. That's only as part of this dispatch an event algorithm that the browser will invoke and inner-invoke until it calls our listener's callback.
Note that this Document parsing step is in itself quite interesting as a task since this is the most obvious place where you will have multiple microtask-checkpoints interleaved inside the "main" task (at each <script> for instance).
The callback function is not queued, it is conceptually stored in the EventTarget's event listener list. In the facts, it's stored in memory, since here the EventTarget is a DOM object (Document), it's probably attached to this DOM object, though this is an implementation detail on which the specs have little to say as this is transparent to us web-devs.
As I hope you now understand better, neither. Task queues and the microtask-queue only store tasks and microtasks, not callbacks. The callbacks are stored elsewhere, depending on what kind of callbacks they are (e.g timers and events are stored in different "conceptual" places), and some task or microtask's steps will then call them.
That depends where this script has been parsed from. If it's inline in a classic
<script>
tag, then that would be the special parsing task we already talked about. If it's from a<script src="url.js">
, then it will be part of a task queued from fetch a classic script, but it can also be part of a microtask, e.g if after anawait
in a module script, or you can even force it to be if you want:And it is even theoretically possible by specs that a microtask becomes a "macro-"task, though no browser does implements this anymore apparently.
All this to say, while I personally find all this stuff fascinating, as a web-dev you shouldn't block yourself on it.