繁体   English   中英

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

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

我正在研究 JS 中的异步行为,并且大部分情况下进展顺利。 我了解执行代码的同步方式,JS的单线程以及诸如setTimeout之类的回调将如何由Web浏览器API计时,然后添加到任务队列中。

事件循环会不断地检查调用栈,只有当它为空时(所有同步代码都已执行),它才会取走已经在任务队列中排队的函数。 将它们推回调用堆栈并执行。

这很简单,这就是下面代码的原因:

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

将 output start, end, timeout

现在,当我开始阅读有关 Promise 的内容时,我了解到它们比常规异步代码(例如超时、间隔、事件侦听器)具有更高的优先级,而是被放置在作业队列/微任务队列中。 事件循环将首先优先考虑该队列并运行所有作业,直到耗尽,然后再进入任务队列。

这仍然是有道理的,可以通过运行看到:

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

这输出start, end, promise, timeout 同步代码执行, then回调从微任务队列被推送到堆栈并执行,任务队列中的 setTimeout 回调任务被推送并执行。 到目前为止一切都很好。

如官方文档所述,我可以围绕上面的示例展开思考,其中 promise 立即同步解决。 如果我们要使用 new 关键字创建 promise 并提供执行程序 function,也会发生同样的情况。 该执行器 function 将同步执行并解析 function。 所以当遇到 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');

上面的代码片段将 output start, promise 1 log, end, promise 1证明执行器同步运行。

这就是我对承诺感到困惑的地方,假设我们有以下代码:

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');

这将导致start, promise 1 log, end, promise 1 如果执行器 function 立即执行,则意味着其中的 setTimeout 将被放入任务队列以供稍后执行。 据我了解,这意味着 promise 目前仍在等待中。 我们得到then方法和其中的回调。 这将被放入作业队列中。 同步代码的 rest 被执行,我们现在有空的调用堆栈。

据我了解,promise 回调现在将具有优先权,但它如何在仍未解决的承诺下执行? promise 应该只在其中的 setTimeout 执行后才能解决,它仍然位于任务队列中。 我听说过,没有任何额外的说明,只有在 promise 得到解决的情况下才会运行,并且从我的 output 我可以看到这是真的,但我不明白在这种情况下如何工作。 我唯一能想到的是一个异常或类似的东西,以及一个任务队列任务在微任务之前获得优先级。

这最终很长,所以我感谢任何花时间阅读和回答这个问题的人。 我很想更好地理解任务队列、作业队列和事件循环,所以不要犹豫发布详细的答案。 先感谢您。

... promise 回调现在将具有优先权...

只有当微任务队列中的任务存在时,它们才会优先于任务队列中的任务。

在示例中:

  • setTimout()任务解析 Promise 之前,没有微任务排队。
  • 任务和微任务不竞争。 它们是连续的。
  • 任务队列和微任务队列(按此顺序)施加的延迟是相加的。

...但是如何执行仍未解决的承诺?

它没有。 .then()回调将仅在 promise 完成后执行,并且该完成取决于setTimeout()放置在任务队列中的任务(即使延迟为零)。

我们得到then方法和其中的回调。 这将被放入作业队列中。

不,如果 promise 仍处于挂起状态,则调用then不会立即将任何内容放入作业队列中。 回调将安装在 promise 上,以便稍后在 promise 完成时执行,就像事件处理程序一样。 只有当您调用resolve()时,它才会真正将其放入作业队列中。

这就像setTimeout一样工作,您在其中写道“ [the] 回调 [...] 将由 Web 浏览器 API 计时,然后添加到任务队列中” - 它不会立即排队以某种方式等待的任务,但是它等待然后将任务排队以执行回调。

暂无
暂无

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

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