简体   繁体   English

了解带有承诺、任务和作业队列的异步 JS

[英]Understanding async JS with promises, task and job queue

I was looking into async behaviour in JS and it was going well for the most part.我正在研究 JS 中的异步行为,并且大部分情况下进展顺利。 I understand the synchronous way of executing code, the single thread of JS and how callbacks such as the one inside setTimeout will be timed by the Web browser API, and later on added to the task queue.我了解执行代码的同步方式,JS的单线程以及诸如setTimeout之类的回调将如何由Web浏览器API计时,然后添加到任务队列中。

The event loop will constantly check the call stack, and only when it is empty (all sync code has executed), it will take functions that have been queued in the task queue.事件循环会不断地检查调用栈,只有当它为空时(所有同步代码都已执行),它才会取走已经在任务队列中排队的函数。 Pushes them back to the call stack and they are executed.将它们推回调用堆栈并执行。

This is pretty straight forward and is the reason why following code:这很简单,这就是下面代码的原因:

console.log('start');
setTimeout(() => console.log('timeout'), 0);
console.log('end');

Will output start, end, timeout .将 output start, end, timeout

Now when I started reading about promises, I understood that they have higher priority than regular async code such as timeout, interval, eventlistener and instead will get placed in the job queue/microtask queue.现在,当我开始阅读有关 Promise 的内容时,我了解到它们比常规异步代码(例如超时、间隔、事件侦听器)具有更高的优先级,而是被放置在作业队列/微任务队列中。 The event loop will first prioritize that queue and run all jobs until exhaustion, before moving on to the task queue.事件循环将首先优先考虑该队列并运行所有作业,直到耗尽,然后再进入任务队列。

This still makes sense and can be seen by running:这仍然是有道理的,可以通过运行看到:

console.log('start');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('end');

This outputs start, end, promise, timeout .这输出start, end, promise, timeout Synchronous code executes, the then callback gets pushed to the stack from the microtask queue and executed, setTimeout callback task from the task queue gets pushed and executed.同步代码执行, then回调从微任务队列被推送到堆栈并执行,任务队列中的 setTimeout 回调任务被推送并执行。 All good so far.到目前为止一切都很好。

I can wrap my head around the example above where the promise gets resolved immediately and synchronously, as told by the official documentation.如官方文档所述,我可以围绕上面的示例展开思考,其中 promise 立即同步解决。 The same would happen if we were to create a promise with the new keyword and provide an executor function.如果我们要使用 new 关键字创建 promise 并提供执行程序 function,也会发生同样的情况。 That executor function will execute synchronously and resolve the function.该执行器 function 将同步执行并解析 function。 So when then is encountered, it can just run asynchronously on the resolved promise.所以当遇到 then 时,它可以在解析的 promise 上异步运行。

console.log('start');

const p1 = new Promise(resolve => {
    console.log('promise 1 log');
    resolve('promise 1');
});

p1.then(msg => console.log(msg));

console.log('end');

The snippet above will output start, promise 1 log, end, promise 1 proving that the executor runs synchronously.上面的代码片段将 output start, promise 1 log, end, promise 1证明执行器同步运行。

And this is where i get confused with promises, let's say we have the following code:这就是我对承诺感到困惑的地方,假设我们有以下代码:

console.log('start');

const p1 = new Promise(resolve => {
    console.log('promise 1 log');
    setTimeout(() => {
        resolve('promise 1');
    }, 0);
});

p1.then(msg => console.log(msg));

console.log('end');

This will result in start, promise 1 log, end, promise 1 .这将导致start, promise 1 log, end, promise 1 If the executor function gets executed right away, that means that the setTimeout within it will get put on the task queue for later execution.如果执行器 function 立即执行,则意味着其中的 setTimeout 将被放入任务队列以供稍后执行。 To my understanding, this means the promise is still pending right now.据我了解,这意味着 promise 目前仍在等待中。 We get to the then method and the callback within it.我们得到then方法和其中的回调。 This will be put in the job queue.这将被放入作业队列中。 the rest of the synchronous code is executed and we now have the empty call stack.同步代码的 rest 被执行,我们现在有空的调用堆栈。

To my understanding, the promise callback will have the priority now but how can it execute with the still unresolved promised?据我了解,promise 回调现在将具有优先权,但它如何在仍未解决的承诺下执行? The promise should only resolve after the setTimeout within it is executed, which still lies inside the task queue. promise 应该只在其中的 setTimeout 执行后才能解决,它仍然位于任务队列中。 I have heard, without any extra clarification that then will only run if the promise is resolved, and from my output i can see that's true, but i do not understand how that would work in this case.我听说过,没有任何额外的说明,只有在 promise 得到解决的情况下才会运行,并且从我的 output 我可以看到这是真的,但我不明白在这种情况下如何工作。 The only thing i can think of is an exception or something similar, and a task queue task getting the priority before the microtask.我唯一能想到的是一个异常或类似的东西,以及一个任务队列任务在微任务之前获得优先级。

This ended up being long so i appreciate anyone taking the time to read and answer this.这最终很长,所以我感谢任何花时间阅读和回答这个问题的人。 I would love to understand the task queue, job queue and event loop better so do not hesitate posting a detailed answer.我很想更好地理解任务队列、作业队列和事件循环,所以不要犹豫发布详细的答案。 Thank you in advance.先感谢您。

... the promise callback will have the priority now... ... promise 回调现在将具有优先权...

Tasks in the microtask queue are given priority over those in the task queue only when they exist.只有当微任务队列中的任务存在时,它们才会优先于任务队列中的任务。

In the example:在示例中:

  • No microtask is queued until after the setTimout() task has resolved the Promise.setTimout()任务解析 Promise 之前,没有微任务排队。
  • The task and microtask are not in competition.任务和微任务不竞争。 They are sequential.它们是连续的。
  • Delays imposed by the task queue and microtask queue (in that order) are additive.任务队列和微任务队列(按此顺序)施加的延迟是相加的。

... but how can it execute with the still unresolved promised? ...但是如何执行仍未解决的承诺?

It doesn't.它没有。 The .then() callback will execute only after the promise is fulfilled, and that fulfillment is dependent on a task placed in the task queue by setTimeout() (even with a delay of zero). .then()回调将仅在 promise 完成后执行,并且该完成取决于setTimeout()放置在任务队列中的任务(即使延迟为零)。

We get to the then method and the callback within it.我们得到then方法和其中的回调。 This will be put in the job queue.这将被放入作业队列中。

No, calling then doesn't put anything in the job queue immediately if the promise is still pending.不,如果 promise 仍处于挂起状态,则调用then不会立即将任何内容放入作业队列中。 The callback will be installed on the promise for execution later when the promise is fulfilled, just like an event handler.回调将安装在 promise 上,以便稍后在 promise 完成时执行,就像事件处理程序一样。 Only when you call resolve() , it actually puts it in the job queue.只有当您调用resolve()时,它才会真正将其放入作业队列中。

This works just like the setTimeout , where you wrote " [the] callback […] will be timed by the Web browser API, and later on added to the task queue " - it doesn't immediately queue a task that somehow waits, but it waits and then queues a task to execute the callback.这就像setTimeout一样工作,您在其中写道“ [the] 回调 [...] 将由 Web 浏览器 API 计时,然后添加到任务队列中” - 它不会立即排队以某种方式等待的任务,但是它等待然后将任务排队以执行回调。

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

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