javascript Promise内部的setTimeout与setTimeout

relj7zay  于 2023-04-04  发布在  Java
关注(0)|答案(2)|浏览(161)

我知道setTimeout()内部的回调函数会一直等待,直到它所连接的计时器到期,并被推入回调队列。另一方面,一个promise一旦被满足或拒绝,它的回调就会被推入一个微任务队列,这个队列具有更高的优先级。
我的问题是哪一次更快:promise中的setTimeout或简单的setTimeout。如果前一个不再放在微任务队列中,为什么setTimeout单独首先运行,而不是相反?

setTimeout(() => {
  console.log('timeout');
}, 1000);

let promise = new Promise(function(resolve, reject) {
  // This is run automatically, let's run resolve after 1 second
  setTimeout(() => resolve('promise!'), 1000);
});

promise.then(
  (result) => console.log(result),
  (err) => console.log(error)
);

// output: timeout -> promise || and not || promise -> timeout

现在让我们假设我忘记了1秒的延迟,现在promise总是首先出现,因为在微任务队列中调度的回调具有更高的优先级

setTimeout(() => {
  console.log('timeout');
}, 0);

let promise = new Promise(function(resolve, reject) {
  // This is run automatically, let's run resolve after 1 second
  // setTimeout(() => resolve('promise!'), 1000);
  resolve('');
});

promise.then(() => {
  console.log('promise');
});
tez616oj

tez616oj1#

setTimeout是以一种方式实现的,它意味着在最小给定延迟之后执行,并且一旦浏览器的线程可以自由执行它。因此,例如,如果您为延迟参数指定0值,并且您认为它会“立即”执行,那么它不会。它会,更准确地说,在下一个事件循环中运行(这是事件循环的一部分-负责执行代码的并发模型)。
让我们以延迟值为0为例。

setTimeout(() => {
  console.log('timeout');
}, 0);

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve('promise!'), 0);
});

promise.then(
  (result) => console.log(result),
  (err) => console.log(error)
);

setTimeout总是首先记录它的结果,因为它肯定会在下一个事件周期中执行。
另一方面,promise中的setTimeout将有2个事件周期,直到控制台日志执行(一个用于promise resolve,另一个用于setTimeout函数中的回调)。
请阅读比指定时间更长的延迟原因-https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified
关于JS事件循环的更多信息-https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

y4ekin9u

y4ekin9u2#

关键是
每次任务退出时,事件循环都会检查任务是否将控制权返回给其他JavaScript代码。如果没有,则会运行微任务队列中的所有微任务。
在下面的第一个示例中,一旦执行主程序的任务退出,由于第二次setTimeout,promise尚未解析,因此没有任何微任务需要处理。然后任务队列被处理,因此首先记录'timeout'。之后,处理第二次setTimeout并解析promise,然后在控制台中打印解析结果。

setTimeout(() => {
  console.log('timeout');
}, 1000);

let promise = new Promise(function(resolve, reject) {
  // This is run automatically, let's run resolve after 1 second
  setTimeout(() => resolve('promise!'), 1000);
});

promise.then(
  (result) => console.log(result),
  (err) => console.log(error)
);

// output: timeout -> promise || and not || promise -> timeout

而在第二个示例中,promise在执行主程序的任务退出后被解析,因此微任务队列首先被处理并记录'promise'。然后任务队列被处理并记录'timeout'。

setTimeout(() => {
  console.log('timeout');
}, 0);

let promise = new Promise(function(resolve, reject) {
  // This is run automatically, let's run resolve after 1 second
  // setTimeout(() => resolve('promise!'), 1000);
  resolve('');
});

promise.then(() => {
  console.log('promise');
});

我强烈推荐阅读这篇文章,这有助于我深入了解任务队列和微任务队列的工作原理。

相关问题