【问题标题】:Event loop, Promise and setTimeout事件循环、Promise 和 setTimeout
【发布时间】:2021-07-31 02:10:51
【问题描述】:

考虑以下代码。我不太明白为什么会这样。

  1. 当代码第一次运行时,它会遇到 setTimeout,因此它会在 Web API(或其他地方)中注册它
  2. 然后它看到了承诺并做同样的工作
  3. 然后遇到阻塞主线程2秒的while循环
  4. 但是,当这个 while 循环执行时,Promise 已被解析并放入微任务队列中。同样,计时器已过期并放置在宏任务(回调)队列中。所以当 while 循环完成时,我们准备好执行承诺和计时器。

我知道微任务队列具有更高的优先级,应该在宏任务队列的回调之前执行,但事实并非如此。请解释原因。

setTimeout(() => {
    console.log("Timer");
}, 1000);

let p = new Promise(res => {
    setTimeout(() => {
        res("Promise");
    }, 1500);
});
p.then(msg => console.log(msg));


let start = new Date().getTime();

let stop = start;

while (stop !== start + 2000){
    stop = new Date().getTime();
}

【问题讨论】:

    标签: javascript asynchronous promise settimeout event-loop


    【解决方案1】:

    链条的强度取决于其最薄弱的环节

    您的第二个setTimeout 确实在您期望的时候开始,但是直到 JS 去寻找它是否已经完成,它才能正式完成。寻找 setTimeout 是否已完成的过程,正式名称为macrotask。承诺解决方案(之后)是一个微任务。

    因此,要解决该承诺需要发生两件事:由 JS 审查的 setTimeout 计时器,以及要解决的承诺。前者是你的瓶颈。

    setTimeout(() => {
        console.log("Timer");
    }, 1000);
    
    let p = new Promise(res => {
        setTimeout(() => {
            res("Promise");
        }, 1500);
        console.log("setTimeout #2 has begun ticking")
    });
    p.then(msg => console.log(msg));
    
    
    let start = new Date().getTime();
    
    let stop = start;
    
    while (stop !== start + 2000){
        stop = new Date().getTime();
    }

    我们通过缩短第二次setTimeout的时间来测试一下

    setTimeout(() => {
        console.log("Timer");
    }, 1000);
    
    let p = new Promise(res => {
        setTimeout(() => {
            res("Promise");
        }, 500);
        console.log("setTimeout #2 has begun ticking")
    });
    p.then(msg => console.log(msg));
    
    
    let start = new Date().getTime();
    
    let stop = start;
    
    while (stop !== start + 2000){
        stop = new Date().getTime();
    }

    第二个程序在“Timer!”之前打印了“Promise”。

    【讨论】:

      【解决方案2】:
      1. 带有“计时器”的setTimeout() 计划在 1 秒后执行。我们称之为 timer1
      2. 一个promise 被创建,executor 函数运行另一个setTimeout(),它将在1.5 秒内解决promise。我们称之为 timer2
      3. .then() 添加了一个回调以在 promise 解决后运行。我们称之为 promiseCallback
      4. 循环开始,将运行 2 秒。
      5. timer1 应该被执行,但线程正忙于执行循环。 timer1 通过将其添加到宏任务队列来延迟,直到线程不忙为止。
      6. timer2 应该被执行,但线程正忙于执行循环。 timer2 通过将其添加到宏任务队列来延迟直到线程不忙。
      7. 循环结束。线程不再忙了。
      8. 微任务队列为空,因此接下来要运行的是宏任务。
      9. timer1 运行。它打印"Timer"
      10. 微任务队列为空,因此接下来要运行的是宏任务。
      11. timer2 运行。它使用值 "Promise" 解析承诺。
      12. 微任务队列有一个任务,所以接下来要运行它。
      13. promiseCallback 运行。它打印出承诺解决的值:"Promise"

      【讨论】:

      • 哇,伙计。很好的解释。谢谢))))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-16
      • 1970-01-01
      • 2018-03-04
      相关资源
      最近更新 更多