Promise为什么要执行呼叫堆栈?

发布于 2025-02-06 14:00:17 字数 501 浏览 1 评论 0原文

function main() {
  console.log("S-1");

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

  new Promise((resolve, reject) => {
    for (let i = 0; i < 10000000000; i++) {}
    resolve("Promise");
  }).then((res) => console.log(res));

  console.log("S-2");
}

// Invoke function
main();

当我运行main()函数时,我将获得的输出是:

'S-1'
'S-2'
'Promise'
'setTimeout'

登录“ S-1”后,存在很大的时间差距,然后几秒钟后,其余的,剩下的时间都会立即记录。 记录“ S-2”之后的时间差距不应该发生吗?

function main() {
  console.log("S-1");

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

  new Promise((resolve, reject) => {
    for (let i = 0; i < 10000000000; i++) {}
    resolve("Promise");
  }).then((res) => console.log(res));

  console.log("S-2");
}

// Invoke function
main();

When I run the main() function, the output I get is:

'S-1'
'S-2'
'Promise'
'setTimeout'

After 'S-1' is logged, there is a big time gap, and then after few seconds, the rest gets logged, at once.
Shouldn't the time gap occur after logging 'S-2'?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

内心旳酸楚 2025-02-13 14:00:17

承诺构造函数内部的函数同步运行,与脚本的其余部分相同(又是)主线程。构建承诺不会导致创建单独的线程。

如果您立即在承诺构造函数内进行一些重型处理,那么重型处理将必须在控制流回到承诺构造器的外部之前完成。在这种情况下,这意味着循环的许多迭代必须在以下之前完成:

  • 构造函数完全完成
  • 构造函数,构造函数解散了
  • 承诺获得
  • 。 Console.log(“ S-2”); 行运行

以获取您想要或期望的输出而不移动日志,您必须将昂贵的代码卸载到其他环境中,例如a

The function inside the Promise constructor runs synchronously, on the same (and only) main thread as the rest of the script. Constructing a Promise doesn't result in a separate thread being created.

If you do some heavy processing immediately inside a Promise constructor, that heavy processing will have to complete before control flow is yielded back to the outside of the Promise constructor. In this case, it means that the many iterations of the loop must finish before:

  • the constructor finishes completely
  • The constructor resolves to a Promise
  • That Promise gets a .then handler attached to it
  • Finally, the console.log("S-2"); line runs

To get the output you're desiring or expecting without moving the logs around, you'd have to offload the expensive code to a different environment, such as to a worker or a server (using a network request).

鲜肉鲜肉永远不皱 2025-02-13 14:00:17

正如@cleantionperformance所说,JavaScript只能处理一个呼叫堆。它需要一劳永逸地完成此线程。为了承诺和超时,它使用工作和任务队列。事件循环将作业队列和任务队列确定优先级。

让我们尝试了解您在呼叫堆和队列方面写的内容。

function main() {
// 1. execute straight forward 
  console.log("S-1"); 

// 2. sets / schedules a timer, the anonymous function is then stored in the callback 
  setTimeout(() => {
    console.log("setTimeout");
  }, 0);

// 3. create a new Promise, with the constructor acting as executor
// executes immediately, as its designed to set the state of the Promise for the then() to react to.
  new Promise((resolve, reject) => {
    for (let i = 0; i < 10000000000; i++) {}
// 3.5 the resolve signals that the execution is finished
// either returns the promise or passes through the then()
    resolve("Promise");

// 4. after the promise execution has been resolved, 
// then() creates another anonymous function, and stores in the callback.
// at this point there are 2 entries in the callback
  }).then((res) => console.log(res));

// 5. once the above Promise executor has been executed, execute this
  console.log("S-2");

// By now, since both the timer and promise execution has been done, 
// the timeout is put into the Task Queue and the Promise then() is  put into the Job Queue.

}

// 0. puts this into the call stack and execute
main();   


// 6. The event loop deques all of the call stack from the job queue and puts it into the main call stack to execute.
// hence, the then() is executed first

// 7. The event loop then deques all of the call stack from the task queue and puts it into the main call stack to execute.
// hence, the timeout function is executed next.

如果您想将其作为回调。

function main() {
  console.log("S-1");

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

  new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("promise");
    }, 1000);
  }).then((res) => console.log(res));

  console.log("S-2");
}

// Invoke function
main();

Reference: https://medium.com/@idineshgarg/let- US-CONSIDER-AN-AXAMPE-A58BB1C11F55

As @CertainPerformance had said, Javascript can only handle one call-stack. It needs to finish this thread once and for all. For promises and timeouts, it uses the job and task queues. The event loop prioritizes the job queue and then the task queue.

Lets try to understand what you wrote in terms of call-stack and queues.

function main() {
// 1. execute straight forward 
  console.log("S-1"); 

// 2. sets / schedules a timer, the anonymous function is then stored in the callback 
  setTimeout(() => {
    console.log("setTimeout");
  }, 0);

// 3. create a new Promise, with the constructor acting as executor
// executes immediately, as its designed to set the state of the Promise for the then() to react to.
  new Promise((resolve, reject) => {
    for (let i = 0; i < 10000000000; i++) {}
// 3.5 the resolve signals that the execution is finished
// either returns the promise or passes through the then()
    resolve("Promise");

// 4. after the promise execution has been resolved, 
// then() creates another anonymous function, and stores in the callback.
// at this point there are 2 entries in the callback
  }).then((res) => console.log(res));

// 5. once the above Promise executor has been executed, execute this
  console.log("S-2");

// By now, since both the timer and promise execution has been done, 
// the timeout is put into the Task Queue and the Promise then() is  put into the Job Queue.

}

// 0. puts this into the call stack and execute
main();   


// 6. The event loop deques all of the call stack from the job queue and puts it into the main call stack to execute.
// hence, the then() is executed first

// 7. The event loop then deques all of the call stack from the task queue and puts it into the main call stack to execute.
// hence, the timeout function is executed next.

If you want to make it a callback.

function main() {
  console.log("S-1");

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

  new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("promise");
    }, 1000);
  }).then((res) => console.log(res));

  console.log("S-2");
}

// Invoke function
main();

Reference: https://medium.com/@idineshgarg/let-us-consider-an-example-a58bb1c11f55

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文