处理 JavaScript 异步函数时的执行顺序问题 (promise)

Execution order question when processing JavaScript asynchronous functions (promise)

提问人:Won Jin Kim 提问时间:6/22/2023 最后编辑:BarmarWon Jin Kim 更新时间:6/22/2023 访问量:65

问:

我想知道下面 JavaScript 代码的执行顺序以及原因。特别是,我想更多地了解进入微任务队列的代码内容,重点是分步

var promise = Promise.resolve();

promise = promise.then(function(rtnVal) {
  console.log('1');
  var promise2 = Promise.resolve();
  promise2 = promise2.then(function(rtnVal) {
    console.log('2');
  });
  promise2 = promise2.then(function(rtnVal) {
    console.log('3');
  });
  console.log('4');
});

promise = promise.then(function(rtnVal) {
  console.log('5');
  var promise2 = Promise.resolve();
  promise2 = promise2.then(function(rtnVal) {
    console.log('6');
  });
  promise2 = promise2.then(function(rtnVal) {
    console.log('7');
  });
  console.log('8');
});

console.log('9');

这是我所做的:9,1,4,2,5,8,3,6,7 ->我想知道为什么它以这个顺序运行”

JavaScript 异步 Promise 任务队列 顺序

评论

0赞 Tim Roberts 6/22/2023
promise.then只是在方便的时候安排一些事情要稍后完成。因此,所有函数都会立即返回。您连续执行 2 次调用,然后同步记录 .此时,排队的任务可以启动。thenthen9
0赞 Won Jin Kim 6/22/2023
仔细想想,从console.log('1')到console.log('4')的回调函数的内容先放到微任务队列中,然后把5~8放到微任务队列中,然后先取9,然后1在队列中,再把2和3放到队列中,这样就会是4, 然后是 5、8、2、3、6、7 等等,为什么不呢?
0赞 prasad_ 6/22/2023
通常,您可能希望提前知道要查找的执行顺序应用程序所需的执行顺序。这将有助于使用正确的构造编写代码。我建议你研究一下文档,并尝试一些使用 Promise 和同步代码的工作示例。此外,请查看 async-await 构造和回调 - 您可以使用它们实现相同的功能。
0赞 Tim Roberts 6/22/2023
我本来以为是 9、1、4、5、8、2、3、6、7,所以唯一让我惊讶的是 2 来得太早了。你确定这就是你的代码的样子吗?
0赞 Won Jin Kim 6/22/2023
是的,这正是表示结果的代码。9、1、4、5、8、2、3、6、7 运行此代码,您将立即看到它。

答:

1赞 trincot 6/22/2023 #1

需要注意的一些事项:

  • 解析 promise 后,任何回调(如果有)都将放在 PromiseJob 队列中then
  • 调用(而不是其回调)时,返回的 promise 始终处于挂起状态,即使该调用是在已解决的 promise 上进行的。这是因为返回的 promise 只能通过执行提供给方法的回调来解析,因为它决定了 promise 的解析方式,但只能异步执行。then()then()then

为了便于分析,我修改了您的脚本,为每个 promise ( to ) 和每个回调函数 (, ...) 命名,但逻辑和输出保持不变:aia_then

var a = Promise.resolve();

var b = a.then(function a_then() {
  console.log(1);
  var c = Promise.resolve();
  var d = c.then(function c_then() {
    console.log(2);
  });
  var e = d.then(function d_then() {
    console.log(3);
  });
  console.log(4);
});

var f = b.then(function b_then() {
  console.log(5);
  var g = Promise.resolve();
  var h = g.then(function g_then() {
    console.log(6);
  });
  var i = h.then(function h_then() {
    console.log(7);
  });
  console.log(8);
});

console.log(9); 

下面是在执行该代码期间发生的一系列事件。

  • 第一列表示正在执行的内容(主脚本、从事件循环启动的函数或从 PromiseJob 队列中取消项目排队的主机)
  • 第二列包含正在计算的当前表达式/语句
  • 使用该名称表示 promise 状态的列:for pending、for fulfilled。ai?F
  • 最后一列描绘了由主机管理的 PromiseJob 队列中存在的内容

来吧:

任务 行动 一个 b c d e f g h PromiseJob 队列
脚本 a = Promise.resolve() F - - - - - - - -
脚本 b = a.then(a_then) F ? - - - - - - - a_then
脚本 f = b.then(b_then) F ? - - - ? - - - a_then
脚本 console.log(9) F ? - - - ? - - - a_then
主机 出列a_then F ? - - - ? - - -
a_then console.log(1) F ? - - - ? - - -
a_then c = Promise.resolve() F ? F - - ? - - -
a_then d = c.then(c_then) F ? F ? - ? - - - c_then
a_then e = d.then(d_then) F ? F ? ? ? - - - c_then
a_then console.log(4) F ? F ? ? ? - - - c_then
a_then 返回解析b F F F ? ? ? - - - c_thenb_then
主机 出列c_then F F F ? ? ? - - - b_then
c_then console.log(2) F F F ? ? ? - - - b_then
c_then 返回解析d F F F F ? ? - - - b_thend_then
主机 出列b_then F F F F ? ? - - - d_then
b_then console.log(5) F F F F ? ? - - - d_then
b_then g = Promise.resolve() F F F F ? ? F - - d_then
b_then h = g.then(g_then) F F F F ? ? F ? - d_theng_then
b_then i = h.then(h_then) F F F F ? ? F ? ? d_then,g_then
b_then console.log(8) F F F F ? ? F ? ? d_then,g_then
b_then 返回解析f F F F F ? F F ? ? d_then,g_then
主机 出列d_then F F F F ? F F ? ? g_then
d_then console.log(3) F F F F ? F F ? ? g_then
d_then 返回解析e F F F F F F F ? ? g_then
主机 出列g_then F F F F F F F ? ?
g_then console.log(6) F F F F F F F ? ?
g_then 返回解析h F F F F F F F F ? h.then
主机 出列h_then F F F F F F F F ?
h_then console.log(7) F F F F F F F F ?
h_then 返回解析i F F F F F F F F F
主机 队列为空 F F F F F F F F F

评论

0赞 Won Jin Kim 6/23/2023
我完全印象深刻。我需要如此详细的解释,但感谢您所做的更多。我会好好分析它,让它对我的工作非常有帮助。
0赞 trincot 6/23/2023
很高兴听到它很有用!如果您愿意,也可以将答案标记为已接受,但这是可选的。
0赞 Won Jin Kim 6/23/2023
我可以再问一个问题吗?如果在“console.log(4);”下面的行中添加一个名为“return e;”的行,则9,1,4,2,5,8,3,6,7的顺序将更改为9,1,4,2,3,5,8,6,7,这是为什么?即使没有返回 promise 的语句,似乎执行了自动返回已解析 promise 的语句,那么结果不应该和第一个代码一样吗?
0赞 trincot 6/23/2023
当回调返回一个恰好是 promise 的值(如 )时,promise 链接的一个非常具体的功能就会发挥作用:在您的示例中,仍然解析,但它使用 promise 解析,这意味着它仍然处于待处理状态(未实现),并且它的命运现在与 的命运相关联(“锁定”),因此不会排队——因为只有在实现时才会发生这种情况。thenebeb_thenb
0赞 trincot 6/23/2023
参见 JS 承诺:履行与解决