考虑以下代码:
function foo() {
console.log('foo');
new Promise(
function(resolve, reject) {
setTimeout(function() {
resolve('RESOLVING');
}, 5000);
}
)
.then(
function(value) {
console.log(value);
}
);
}
foo();
我试图正确理解这里发生的事情:
- 在执行时
new Promise
“执行器函数”直接运行,当setTimeout
被调用时,将安排一个向“事件队列”添加新条目的操作(5 秒后)
- 因为打电话给
then
将对传递的函数(记录到控制台)的调用添加到“作业队列”的操作被组织为在Promise
已解决
- 当。。。的时候
setTimeout
执行回调(在事件循环的某个时间点上),Promise
已解决并基于第 2 点,即函数参数then
调用被添加到“作业队列”并随后执行。
请注意,我说“作业队列”是因为有些事情我不确定;哪个“作业队列是?”。据我理解,“作业队列”链接到“事件队列”上的条目。那么这会是setTimeout
上面例子中的条目?
假设之前(和之后)没有其他事件添加到“事件队列”中setTimeout
添加了 的回调,到那时主代码的条目(对 foo 的调用)是否已经(通常)消失(运行至完成),因此除了setTimeout
是为了then
要链接到的“作业队列”条目?
- 在执行时
new Promise
“执行器函数”直接运行,当setTimeout
被调用时,将安排一个向“事件队列”添加新条目的操作(5 秒后)
是的。更具体地说,调用setTimeout
使用浏览器的定时器机制安排定时器;大约五秒钟后,计时器机制将一个作业添加到主作业队列中,该队列将调用您的回调。
- 因为打电话给
then
将对传递的函数(记录到控制台)的调用添加到“作业队列”的操作被组织为在Promise
已解决
Right. then
(使用单个参数)向 Promise 添加一个履行处理程序(并创建它返回的另一个 Promise)。当承诺解决时,调用处理程序的作业将被添加到作业队列中(但它是一个不同的作业队列)。
- 当。。。的时候
setTimeout
执行回调(在事件循环的某个时间点上),Promise
已解决并基于第 2 点,即函数参数then
调用被添加到“作业队列”并随后执行。
是的,但不是同一个作业队列。 :-)
主作业队列是事件处理程序和计时器回调等的所在。主事件循环从队列中选取一个作业,运行它直至完成,然后选取下一个作业,依此类推,如果没有要运行的作业,则空闲。
一旦作业运行完成,another循环运行,它负责运行在该主作业期间安排的任何待处理的承诺作业。
在 JavaScript 规范中,主作业队列称为 ScriptJobs,承诺回调作业队列称为 PromiseJobs。在 ScriptJob 结束时,所有已排队的 PromiseJobs 将在下一个 ScriptJob 之前执行。 (在 HTML 规范中,它们的名称是“任务”[或“宏任务”] 和“微任务”。)
是的,这确实意味着如果作业 A 和作业 B 都已排队,然后作业 A 被选取并安排承诺回调,则运行该承诺回调before即使作业 B 首先排队(在主队列中),作业 B 仍会运行。
请注意,我说“作业队列”是因为有些事情我不确定;这是哪个“作业队列?”
希望我上面已经介绍过了。基本上:
- 初始脚本执行、事件处理程序、计时器和
requestAnimationFrame
回调会排队到 ScriptJobs 队列(主要队列);它们是“宏任务”(或简称“任务”)。
- Promise 回调会排队到 PromiseJobs 队列中,该队列会一直被处理,直到任务结束时为空。也就是说,承诺回调是“微任务”。
据我理解,“作业队列”链接到“事件队列”上的条目。
这些只是同一事物的不同名称。 JavaScript 规范使用术语“作业”和“作业队列”。 HTML 规范使用“任务”、“任务队列”和“事件循环”。事件循环负责从 ScriptJobs 队列中获取作业。
那么这会是setTimeout
上面例子中的条目?
当计时器触发时,作业将被安排在 ScriptJobs 队列中。
假设之前(和之后)没有其他事件添加到“事件队列”中setTimeout
添加了 的回调,到那时主代码的条目(对 foo 的调用)是否已经(通常)消失(运行至完成),因此除了setTimeout
是为了then
要链接到的“作业队列”条目?
基本上是的。让我们来看看:
- 浏览器加载脚本并向 ScriptJobs 添加作业以运行脚本的顶级代码。
- The event loop picks up that job and runs it:
- 该代码定义了
foo
并调用它。
- Within
foo
,你做console.log
然后创建一个承诺。
- Promise 执行器安排一个计时器回调:将计时器添加到浏览器的计时器列表中。它尚未对作业进行排队。
-
then
向承诺添加履行处理程序。
- 那个工作就结束了。
- 大约五秒钟后,浏览器会向 ScriptJobs 添加一个作业来调用计时器回调。
- The event loop picks up that job and runs it:
- 回调解析 Promise,这会将 Promise 履行处理程序调用添加到 PromiseJobs 队列。
- That job ends, but with entries in PromiseJobs, so the JavaScript engine loops through those in order:
- 它获取履行处理程序回调作业并运行它;履行处理程序所做的
console.log
- 这项工作现在已经完全完成了。
更多探索:
- JavaScript 规范中的作业和作业队列
- HTML5 规范中的事件循环
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)