简体   繁体   English

事件循环、Promise 和 setTimeout

[英]Event loop, Promise and setTimeout

Consider the following code.考虑以下代码。 I don't quite understand why it works this way.我不太明白为什么它会这样工作。

  1. When the code runs first it encounters setTimeout , so it registers it in web APIs (or somewhere else)当代码第一次运行时,它遇到了setTimeout ,所以它会在 Web API(或其他地方)中注册它
  2. Then it sees promise and does the same job然后它看到了承诺并做同样的工作
  3. Then it encounters while loop that blocks main thread for 2 second然后它遇到阻塞主线程2秒的while循环
  4. However by the time this while loop is executed the Promise has been resolved and placed inside microtask queue.然而,当这个 while 循环被执行时,Promise 已经被解析并放置在微任务队列中。 Likewise timer has been expired and placed inside macrotask (callback) queue.同样,计时器已过期并放置在宏任务(回调)队列中。 So when while loop is done we have promise and timer ready to be executed.所以当while循环完成时,我们已经准备好执行promise和timer了。

I know that microtask queue has higher priority and should be executed before callbacks from macrotask queue, however it is not the case.我知道微任务队列具有更高的优先级,应该在宏任务队列的回调之前执行,但事实并非如此。 Please explain why.请解释原因。

 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(); }

A chain is only as strong as its weakest link链条的强度取决于它最薄弱的环节

Your second setTimeout indeed does begin when you expected it to, but until JS goes looking for whether it has finished, it can't officially finish.你的第二个setTimeout确实在你预期的时候开始了,但是直到 JS 去寻找它是否已经完成,它才能正式完成。 That process of looking for whether a setTimeout has finished, is officially a macrotask .寻找 setTimeout 是否已完成的过程,正式是一个macrotask The promise resolution (after that) is a microtask.承诺决议(在那之后)是一个微任务。

So for that promise to resolve requires two things to happen: setTimeout timer to be reviewed by JS, and the promise to resolve.因此,要解决该承诺需要发生两件事:由 JS 审查的 setTimeout 计时器,以及要解决的承诺。 The former is the bottleneck in your case.前者是您的情况的瓶颈。

 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(); }

Let's test it by shortening the time of the second setTimeout我们通过缩短第二次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(); }

The second program has the "Promise" printed before "Timer!".第二个程序在“Timer!”之前打印了“Promise”。

  1. The setTimeout() with "Timer" is scheduled for 1 second later.带有“Timer”的setTimeout()安排在 1 秒后。 Let's call this timer1 .我们称之为timer1
  2. A promise is created and the executor function runs another setTimeout() that will resolve the promise in 1.5 seconds.一个承诺被创建,执行器函数运行另一个setTimeout()将在 1.5 秒内解决承诺。 Let's call this timer2 .我们称之为timer2
  3. The .then() adds a callback to run after the promise is resolved. .then()添加了一个回调以在承诺解决后运行。 Let's call this promiseCallback .我们称之为promiseCallback
  4. The loop starts that will run for 2 seconds.循环开始,将运行 2 秒。
  5. timer1 is supposed to be executed but the thread is busy executing the loop. timer1应该被执行,但线程正忙于执行循环。 timer1 is delayed until the thread is not busy by adding it to the macrotask queue. timer1通过将其添加到宏任务队列来延迟到线程不忙。
  6. timer2 is supposed to be executed but the thread is busy executing the loop. timer2应该被执行,但线程正忙于执行循环。 timer2 is delayed until the thread is not busy by adding it to the macrotask queue. timer2通过将其添加到宏任务队列来延迟直到线程不忙。
  7. Loop ends.循环结束。 Thread is not busy any more.线程不再忙碌。
  8. The microtask queue is empty, so the next thing to run is a macrotask.微任务队列是空的,所以接下来要运行的是宏任务。
  9. timer1 runs. timer1运行。 It prints "Timer" .它打印"Timer"
  10. The microtask queue is empty, so the next thing to run is a macrotask.微任务队列是空的,所以接下来要运行的是宏任务。
  11. timer2 runs. timer2运行。 It resolves the promise with the value "Promise" .它使用值"Promise"解析承诺。
  12. The microtask queue has one task, so that is the next thing to run.微任务队列有一个任务,所以接下来要运行它。
  13. promiseCallback runs. promiseCallback运行。 It prints the value that the promise was resolve with: "Promise" .它打印承诺解决的值: "Promise"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM