简体   繁体   English

订购 JavaScript 承诺

[英]Ordering in JavaScript promises

I have stumbled on the example of code related to Promises in JavaScript and can't understand why will it type ABC instead of CAB.我偶然发现了 JavaScript 中与 Promises 相关的代码示例,无法理解为什么它会输入 ABC 而不是 CAB。 Here is the code:这是代码:

p.then(function() {
  p.then(function() {
    console.log("C");
  });
  console.log("A");
});
p.then(function() {
  console.log("B");
}); //  A   B   C

I may be mistaking that it isn't important for my question what code is in p.我可能误认为 p 中的代码对我的问题并不重要。

The .then() method of class Promise() sets some code (a function) to be executed at some moment in the future, when the promise is resolved. class Promise()的 .then .then()方法设置一些代码(一个函数)在未来某个时刻执行,当 promise 被解析时。

A Promise is what its name says: the promise of a result that will be available at some time in the future, when an operation that has already started and runs asynchronously completes. Promise就是它的名字所说的:promise 的结果将在未来某个时间可用,此时已经开始并异步运行的操作完成。 The code that started the asynchronous operation (and created the promise) can continue doing what it has to do without waiting for the async operation to complete.启动异步操作(并创建承诺)的代码可以继续做它必须做的事情,而无需等待异步操作完成。

Each invocation of .then() adds a function to a queue of functions to be executed when the promise is resolved (ie when the asynchronous operation completes with success).每次调用 .then .then()都会将 function 添加到要在解决 promise 时(即异步操作成功完成时)执行的函数队列中。 Each promise has its own queue.每个 promise 都有自己的队列。

The top-level code you posted calls p.then() twice.您发布的顶级代码调用p.then()两次。 After it executes, the queue of p contains the following functions waiting to be executed:在它执行之后, p的队列包含以下等待执行的函数:

function() {
  p.then(function() {
    console.log("C");
  });
  console.log("A");
}

function() {
  console.log("B");
}

When p is resolved it calls these two functions, in order.p被解析时,它按顺序调用这两个函数。
The first function puts a call to another function at the end of the queue (by calling p.then() ) then it prints A .第一个 function 调用队列末尾的另一个 function (通过调用p.then() )然后它打印A When it ends, the queue contains the following functions, waiting to be called:当它结束时,队列包含以下函数,等待被调用:

function() {
  console.log("B");
}

function() {
  console.log("C");
}

The function that displays A has been removed from the queue because it has been executed.显示A的 function 已从队列中删除,因为它已被执行。

Then these functions are executed in the order they were placed on the queue and, of course, they print B and C (in this order).然后这些函数按照它们放入队列的顺序执行,当然,它们打印BC (按此顺序)。 Each of them is removed from the queue after it is executed.它们中的每一个在执行后都会从队列中删除。

The callbacks you are passing to then are always called asynchronously:您传递给then的回调总是被异步调用:

p.then(() => console.log(2));
console.log(1);

This is the expected behaviour for asynchronous code, when p fulfills after a timeout or so, and promises do not deviate from that behaviour even if p is an already-fulfilled promise.这是异步代码的预期行为,当p在超时后实现时,即使p是已经实现的 promise,promise 也不会偏离该行为。

Other than that, callbacks attached to a promise will just be scheduled in the same order as the respective then calls happened, so A will always log before B .除此之外,附加到 promise 的回调将按照与相应then调用发生的顺序相同的顺序安排,因此A将始终在B之前记录。

Assuming p is a resolving promise假设 p 是解析 promise

const p = Promise.resolve();

Then calling p.then(f1) would issue f1 for execution once the JS thread is available (remember: js is executed in a single thread!) .然后调用p.then(f1)将在 JS 线程可用时发出f1执行(请记住:js 在单个线程中执行!)

Next, p.then(f2) would enqueue f2 for execution.接下来, p.then(f2)f2排入队列以执行。

Once the end of the file is reached the queue is executed.一旦到达文件末尾,就会执行队列。 f1() first enques another function f3 using the promise and then prints A . f1()首先使用 promise 查询另一个 function f3然后打印A Next, f2 is in the queue, printing B .接下来, f2在队列中,打印B Then the last f3 is executed to print C .然后执行最后一个f3以打印C

You can maybe better understand it when adding more tracing:添加更多跟踪时,您可能会更好地理解它:

const p = Promise.resolve();

console.log('1');
p.then(function() {
  console.log('2');
  p.then(function() {
    console.log('3');
    console.log("C");
  });
  console.log('4');
  console.log("A");
});
console.log('5');
p.then(function() {
  console.log('6');
  console.log("B");
}); //  A   B   C
console.log('7');

prints (I added | marks to hint where a different function runs):打印(我添加了|标记以提示不同的 function 运行的位置):

1 5 7 | 2 4 A | 6 B | 3 C 
main  | f1    | f2  | f3

Why does it go in this order?为什么按这个顺序是go? Promises are asynchronous. Promise 是异步的。 The code does not sit and wait for the them to be executed, it just stores it and continues on.代码不会坐下来等待它们被执行,它只是存储它并继续。

You register two thens (A and B).您注册了两个 then(A 和 B)。 The promise is done, they are executed. promise 完成,它们被执行。 The first one runs (A), it registers another then (C).第一个运行(A),然后注册另一个(C)。 The second on runs (B), and then the third one runs (C).第二个运行(B),然后第三个运行(C)。

 var p = new Promise(resolve => window.setTimeout(resolve, 500)) console.log('registering A') p.then(function() { console.log('registering C') p.then(function() { console.log("C"); }); console.log("A"); }); console.log('registering B') p.then(function() { console.log("B"); });

let's break this down, line by line让我们逐行分解

// .then triggers the 1st stack call and jumps to the next line of sync code
p.then(function() {
  // triggers the 3rd stack call 
  p.then(function() {
    // prints "C" from 3rd stack call
    console.log("C");
  });
  // prints "A" from 1st stack call
  console.log("A");
});
// jumps to this line of sync code, then triggers the 2nd stack call 
p.then(function() {
  // prints "B" from 2nd stack call
  console.log("B");
}); //  A   B   C

what @Bergi says is right about async calls being placed in the call stack -- meaning the js engine will push forward with what synchronous code is left to execute then circle back to the call stack. @Bergi 所说的关于将异步调用放在调用堆栈中的说法是正确的——这意味着 js 引擎将推进剩下的同步代码执行,然后返回调用堆栈。

In your example, when the 1st async p.then is called, it jumps to the next synchronous line of code which happens to triggers the 2nd stack call.在您的示例中,当调用第一个异步p.then时,它会跳转到下一个同步代码行,该代码恰好触发了第二个堆栈调用。 when there is no synchronous code left, the js engine looks for 1st stack call in the stack.当没有同步代码时,js引擎在堆栈中查找第一个堆栈调用。 it sees p.then which triggers the 3rd stack call and moves to the next of sync code console.log("A");它看到p.then触发了第三个堆栈调用并移动到下一个同步代码console.log("A"); . . at this point no sync code is left, so the engine goes to the call stack again and executes the next stack call it sees and console.log("B");此时没有留下任何同步代码,因此引擎再次进入调用堆栈并执行它看到的下一个堆栈调用和console.log("B"); and again with no sync code left, it reaches into the call stack and sees the 3rd stack call and executes console.log("C")再次没有同步代码,它进入调用堆栈并看到第三个堆栈调用并执行console.log("C")

To explain better I will tag all your three promises.为了更好地解释,我将标记你所有的三个承诺。

p.then(function() {
  p.then(function() {
    console.log("C");
  }); // Z
  console.log("A");
}); // X

p.then(function() {
  console.log("B");
}); // Y

First you should know promises are handled asynchronously.They either get resolved or rejected.首先,您应该知道promise是异步处理的。它们要么被解决,要么被拒绝。 In your case they will be resolved immediately and pushed to a queue called callback queue where they will be picked and executed when callstack is empty.在您的情况下,它们将立即被解析并推送到称为callback queue的队列中,当callstack为空时,它们将被拾取并执行。

So, when your code runs it registers first two, X and Y .因此,当您的代码运行时,它会注册前两个XY It pushes them in the callback queue , which is based on FIFO , whatever is pushed first gets executed first.它将它们推送到基于FIFOcallback queue中,首先推送的内容将首先执行。

So X start executing, but in X you have another promise Z so it also get registered, and pushed back to Y in the queue.所以X开始执行,但在X中你有另一个 promise Z所以它也被注册,并推回队列中的Y After it, A gets printed.之后, A被打印出来。

Now your second promise Y gets executed and B gets printed, and finally Z gets executed and C gets printed.现在你的第二个 promise Y被执行, B被打印,最后Z被执行, C被打印。

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

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