javascript promise,事件循环和作业队列

时间:2019-04-14 15:24:32

标签: javascript

考虑以下代码:

function foo() {
    console.log('foo');

    new Promise(
        function(resolve, reject) {
            setTimeout(function() {
                resolve('RESOLVING');
            }, 5000);
        }
    )
    .then(
        function(value) {
            console.log(value);
        }
    );
}
foo();

我正在尝试正确理解此处发生的情况:

  1. 在执行new Promise时,直接运行“ executer函数”,并且在调用setTimeout时,计划将新条目添加到“事件队列”的操作(5秒钟后)< / li>
  2. 由于对then的调用被构造为在解析Promise之后发生的对传递给函数的调用的操作(记录到控制台),该操作被添加到“作业队列”中< / li>
  3. 在执行setTimeout回调时(在事件循环的某个滴答处),将解析Promise并基于第2点,向then调用添加函数参数进入“作业队列”并随后执行。

注意,我之所以说[一个“工作队列”],是因为我不确定某些事情;哪个“是工作队列?”。据我了解,“作业队列”链接到“事件队列”上的条目。那就是上面示例中的setTimeout条目吗? 假设在添加setTimeout的回调之前(和之后),没有其他事件添加到“事件队列”中,那么主代码(对foo的调用)的条目通常不会消失(到那时为止),因此setTimeout的“作业队列”条目要链接到then之外没有其他条目了?

1 个答案:

答案 0 :(得分:2)

  
      
  1. 在执行new Promise时,直接运行“ executer函数”,并且在调用setTimeout时,计划将新条目添加到“事件队列”的操作(5秒钟后)< / li>   

是的。更具体地说,调用setTimeout可以使用浏览器的计时器机制安排计时器;大约五秒钟后,计时器机制将一个作业添加到主作业队列中,该作业将调用您的回调。

  
      
  1. 由于对then的调用被构造为在解析Promise之后发生的对传递给函数的调用的操作(记录到控制台),该操作被添加到“作业队列”中< / li>   

对。 then(带有单个参数)将一个实现处理程序添加到Promise(并创建它返回的另一个Promise)。当承诺解决后,将调用处理程序的作业添加到作业队列中(但这是一个不同的作业队列)。

  
      
  1. 在执行setTimeout回调时(在事件循环的某个滴答处),将解析Promise并基于第2点,向then调用添加函数参数进入“作业队列”并随后执行。
  2.   

是的,但是工作队列不同。 :-)

主作业队列是事件处理程序和计时器回调之类的地方。主事件循环从队列中拾取一个作业,将其运行到完成,然后拾取下一个作业,依此类推,如果没有要运行的作业,则空转。

一旦作业运行完毕,就会运行另一个循环,该循环负责运行在该主要作业中计划的所有待处理的承诺作业。

在JavaScript规范中,主作业队列称为ScriptJobs,而promise回调作业队列为PromiseJobs。在ScriptJob的末尾,将在下一个ScriptJob之前执行已排队的所有PromiseJob。 (在HTML规范中,它们的名称是“任务”(或“宏任务”)和“微任务”。)

是的,这确实意味着,如果作业A和作业B都排队,然后作业A被接起并安排了承诺回调,则该承诺回调将在运行作业 之前运行,即使作业B首先(在主队列中)排队。

  

注意,我之所以说[一个“工作队列”],是因为我不确定某些事情;哪个“是工作队列?”

希望我已经在上面介绍了。基本上:

  • 初始脚本执行,事件处理程序,计时器和requestAnimationFrame回调被排队到ScriptJobs队列(主要队列)中;它们是“宏任务”(或简称为“任务”)。
  • Promise回调将排队到PromiseJobs队列中,该队列将一直处理到任务结束时为空。也就是说,承诺回调是“微任务”。
  

按照我的理解,“作业队列”链接到“事件队列”上的条目。

这些只是同一事物的不同名称。 JavaScript规范使用术语“作业”和“作业队列”。 HTML规范使用“任务”,“任务队列”和“事件循环”。事件循环是从ScriptJobs队列中拾取作业的地方。

  

那将是上面示例中的setTimeout条目吗?

当计时器触发时,将在ScriptJobs队列中安排作业。

  

假定在添加setTimeout的回调之前(和之后)没有将其他事件添加到“事件队列”中,那么通常不会编写主代码的条目(对foo的调用) )到那时为止(运行完成),因此setTimeout的“作业队列”条目将与then一样没有其他条目可以链接?

基本上是。让我们开始吧:

  • 浏览器将加载脚本并将作业添加到ScriptJobs以运行脚本的顶级代码。
  • 事件循环拾取并运行该作业:
    • 该代码定义了foo并对其进行了调用。
    • foo内,您进行console.log,然后创建一个诺言。
    • promise执行程序安排计时器回调:将计时器添加到浏览器的计时器列表中。它还没有排队工作。
    • then向诺言添加履行处理程序。
    • 那项工作结束了。
  • 大约五秒钟后,浏览器将一个作业添加到ScriptJobs来调用计时器回调。
  • 事件循环拾取并运行该作业:
    • 该回调函数解析了Promise,从而向PromiseJobs队列添加了PromiseJobs队列。
    • 该工作结束,但是PromiseJobs中有条目,因此JavaScript引擎按顺序遍历这些条目:
      • 它将拾取实现处理程序回调作业并运行它;履行处理程序执行console.log
    • 这项工作现在已经完全完成。

更多探索: