可以在“任务队列”中的元素之后完成“作业队列”中的元素吗?

huangapple go评论62阅读模式
英文:

Can element in JOB QUEUE be completed after element in TASK QUEUE?

问题

I understand that you'd like a translation, but it seems you've provided a detailed technical explanation related to JavaScript execution queues. If you have a specific question or need a translation of a particular part, please let me know, and I'll be happy to assist with that.

英文:

community! I've been recently discovering how JavaScript works and came across interesting moment with order of elements being executed in Job Queue and Task Queue.
As we all know, Job Queue has higher priority then Task Queue. But is it correct, that if async function like Promise.resolve depends on lower priority functions in Task Queue, than before completing the async function, we need to execute all functions from Task Queue ?

This can be seen on the example I've provided below:

setTimeout(()=>{
    console.log('1');
}, 0);
(https://i.stack.imgur.com/lb9Zr.png)

Promise.resolve('2').then(console.log);

console.log('3');

This code will have to come through the next steps:

  1. setTimeout is added to call stack
  2. setTimeout is pushed to WebAPI and popped from call stack
  3. Promise.resolve, after being recognized as async function returning promise,
    is pushed in Job Queue and in the same time setTimout callback is pushed in Task Queue
  4. console.log('3') is pushed on the call stack and executed and popped from call stack
  5. As call stack is empty, event loop pushes Promise.resolve on call stack and produces console.log function to be executed
  6. When the previous functions are popped, only then setTimeout callback will be pushed on call stack and executed

so in the console we have following output:
3
2
1
(https://i.stack.imgur.com/0eApX.png)

However, if we modify the code to be:

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

Promise.resolve(setTimeout(()=>{
    console.log('2');        
}));

console.log('3');

We will have output:
3
1
2

(https://i.stack.imgur.com/bvPEp.png)

So, I suggest next steps:

  1. setTimeout is added to call stack
  2. setTimeout is pushed to WebAPI and popped from call stack
  3. Promise.resolve, after being recognized as async function returning promise,
    is pushed in Job Queue and in the same time setTimout callback is pushed in Task Queue
  4. console.log('3') is pushed on the call stack and executed and popped from call stack
  5. As call stack is empty, event loop pushes Promise.resolve on call stack, however this function depends on setTimeout which goes to WebAPI and then pushed in Task Queue.
    !!! And it is the most interesting part: elements in Task Queue executed using FIFO (first-in first-out) principle, so, as I suggest, event loop is forced to push first setTimout callback on call stack, which is blocking the one on which Promise.resolve is depending
  6. After first setTimeout callback is executed, popped -> setTimeout callback on which Promise.resolve depends now can be pushed, executed and popped.

To sum up, is it correct, that if async function like Promise.resolve depends on lower priority functions in Task Queue, than before completing the async function, we need to execute all functions from Task Queue ?
P.S. I've attached screenshots of code + result using chrome console

答案1

得分: 0

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

Promise.resolve(setTimeout(() => {
    console.log('2');
}));

console.log('3');

这个示例可能不是您预期的 - 您在此处同步调用了setTimeout,并创建了一个以其timeoutId为参数的已解决的Promise。这与以下代码相同:

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

let id = setTimeout(() => {
    console.log('2');
});
Promise.resolve(id);

console.log('3');

不深入讨论规范/平台术语:Promise的解析总是在I/O和类似计时器的操作之前发生。每当平台运行I/O处理程序时,它们会在每个操作之后“运行所有微任务”(因此您可以使用微任务“饿死事件循环” - 在Node文档中,我们甚至对process.nextTick有一个警告)。

英文:
setTimeout(()=>{
    console.log('1');
}, 0);

Promise.resolve(setTimeout(()=>{
    console.log('2');        
}));

console.log('3');

This example is probably not what you intended - you are calling setTimeout synchronously here and creating a promise fulfilled to its timeoutId. It's the same as:

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

let id = setTimeout(()=>{
    console.log('2');        
});
Promise.resolve(id);

console.log('3');

Without getting into spec/platform terminology too much: Promise resolution always comes before I/O and stuff like timers. Whenever platforms run handlers for I/O they will "run all microtasks" after each operation (so you can "starve the event loop" with microtasks - we even have a warning for process.nextTick in the docs in Node).

huangapple
  • 本文由 发表于 2023年5月17日 21:06:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76272452.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定