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

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

Execution order question when processing JavaScript asynchronous functions (promise)

问题

9, 1, 4, 5, 8, 2, 3, 6, 7 - 这个顺序是因为 JavaScript 中的 Promise 机制导致了微任务队列中的代码在主线程代码之后执行。微任务队列中的代码按照它们进入队列的顺序依次执行。

以下是代码执行的详细顺序:

  1. 首先,主线程开始执行代码,遇到 var promise = Promise.resolve();,这是一个同步操作,它会立即创建一个已解决的 Promise 对象并赋给变量 promise。然后执行 console.log('9'); 输出 "9"。

  2. 继续往下执行,遇到 promise = promise.then(function(rtnVal) { ...,这是一个 Promise 链,但它的回调函数不会立即执行。主线程将此任务添加到微任务队列。

  3. 主线程继续往下执行,遇到 console.log('1');,输出 "1"。

  4. 接下来,进入 Promise 链中的回调函数,遇到 var promise2 = Promise.resolve();,也会创建一个已解决的 Promise 对象并赋给变量 promise2。然后,遇到 console.log('4'); 输出 "4"。

  5. 继续在 Promise 链中执行,将两个 promise2.then(...) 也添加到微任务队列。

  6. 主线程执行完当前任务后,开始处理微任务队列中的任务。微任务队列中的任务按照它们被添加的顺序执行。

  7. 首先,执行 promise.then(...) 的回调函数,遇到 console.log('5'); 输出 "5"。

  8. 接下来,再次进入 Promise 链中的回调函数,遇到 console.log('2'); 输出 "2"。

  9. 继续执行 Promise 链中的任务,遇到 console.log('3'); 输出 "3"。

  10. 然后,执行上一次 Promise 链中的 promise2.then(...) 回调函数,遇到 console.log('6'); 输出 "6"。

  11. 最后,执行 Promise 链中的另一个 promise2.then(...) 回调函数,遇到 console.log('7'); 输出 "7"。

因此,最终的输出顺序是 9, 1, 4, 5, 8, 2, 3, 6, 7,这是因为微任务队列中的任务会在主线程任务执行完毕后按照它们的顺序执行。

英文:

I'd like to know the order in which the JavaScript code below is executed and why. In particular, I would like to learn more about the contents of the code that goes into the microtask queue, focusing on step-by-step

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

var promise = Promise.resolve();

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

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

console.log(&#39;9&#39;);

<!-- end snippet -->

Here's what I did: 9,1,4,2,5,8,3,6,7 ->I'm wondering why it runs in this order`

答案1

得分: 1

以下是您要翻译的部分:

  • 当一个 promise 被解决时,任何 then 回调函数(如果有的话)都会放在 PromiseJob 队列中。
  • 当调用 then()(而不是它的回调函数)时,返回的 promise 始终 处于挂起状态,即使在已解决的 promise 上调用了 then()。这是因为返回的 promise 只能通过执行传递给 then 方法的回调函数来解决,而这只能异步执行。

为了便于分析,我修改了您的脚本,为每个 promise(ai)和每个回调函数(a_then,...)分配了一个名称,但逻辑和输出保持不变。

以下是代码执行期间发生的事件序列:

任务 动作 a b c d e f g h i 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_then, b_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_then, d_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_then, g_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
英文:

Some things to be aware of:

  • When a promise is resolved, any then callbacks (if any) are put on the PromiseJob queue
  • When then() is called (not its callback), the returned promise is always pending, even if that then() call is made on a resolved promise. This is because the returned promise can only be resolved by executing the callback that is given to the then method since it determines how the promise will resolve, but which can only execute asynchronously.

To ease the analysis, I modified your script to give a name to each promise (a to i) and to each callback function (a_then, ...), but the logic and output remains the same:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

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

<!-- end snippet -->

Here is a sequence of events that happen during the execution of that code.

  • The first column represents what is executing (the main script, a function initiated from the event loop, or the host that dequeues an item from the PromiseJob queue)
  • The second column has the current expression/statement being evaluated
  • The columns a to i represent the state of the promise with that name: ? for pending, F for fulfilled.
  • The last column pictures what is present in the PromiseJob queue, managed by the host

Here we go:

Task Action a b c d e f g h i PromiseJob queue
Script a = Promise.resolve() F - - - - - - - -
Script b = a.then(a_then) F ? - - - - - - - a_then
Script f = b.then(b_then) F ? - - - ? - - - a_then
Script console.log(9) F ? - - - ? - - - a_then
Host dequeue 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 return resolves b F F F ? ? ? - - - c_then, b_then
Host dequeue c_then F F F ? ? ? - - - b_then
c_then console.log(2) F F F ? ? ? - - - b_then
c_then return resolves d F F F F ? ? - - - b_then, d_then
Host dequeue 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_then, g_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 return resolves f F F F F ? F F ? ? d_then, g_then
Host dequeue 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 return resolves e F F F F F F F ? ? g_then
Host dequeue g_then F F F F F F F ? ?
g_then console.log(6) F F F F F F F ? ?
g_then return resolves h F F F F F F F F ? h.then
Host dequeue 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 return resolves i F F F F F F F F F
Host queue is empty F F F F F F F F F

huangapple
  • 本文由 发表于 2023年6月22日 10:30:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76528242.html
匿名

发表评论

匿名网友

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

确定