Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/478.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript承诺中的排序_Javascript - Fatal编程技术网

JavaScript承诺中的排序

JavaScript承诺中的排序,javascript,Javascript,我偶然发现了JavaScript中与承诺相关的代码示例,不明白为什么它会键入ABC而不是CAB。 代码如下: p、 然后功能{ p、 然后功能{ console.logC; }; console.logA; }; p、 然后功能{ console.logB; }; // A、B、C 我可能错误地认为,对于我的问题,p中的代码是什么并不重要。您传递给的回调总是异步调用的: p.then(() => console.log(2)); console.log(1); 这是异步代码的预期行为,

我偶然发现了JavaScript中与承诺相关的代码示例,不明白为什么它会键入ABC而不是CAB。 代码如下:

p、 然后功能{ p、 然后功能{ console.logC; }; console.logA; }; p、 然后功能{ console.logB; }; // A、B、C
我可能错误地认为,对于我的问题,p中的代码是什么并不重要。

您传递给的回调总是异步调用的:

p.then(() => console.log(2));
console.log(1);
这是异步代码的预期行为,当p在大约一个超时后实现时,承诺不会偏离该行为,即使p是已经实现的承诺


除此之外,附加到承诺的回调将按照与相应的then调用相同的顺序进行调度,因此a将始终在B之前进行日志记录。

假设p是一个解析承诺

const p = Promise.resolve();
然后调用p.thenf1将在JS线程可用时发出f1以执行记住:JS是在单个线程中执行的

接下来,p.thenf2将把f2排队等待执行

到达文件末尾后,将执行队列。f1首先使用承诺命令另一个函数f3,然后打印A。接下来,f2在队列中,打印B。然后执行最后一个f3打印C

添加更多跟踪时,您可能会更好地理解它:

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');
我添加了|标记以提示不同函数在何处运行:

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

为了更好地解释,我会把你的三个承诺都贴上标签

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

p.then(function() {
  console.log("B");
}); // Y
首先,您应该知道这些问题是异步处理的。它们要么得到解决,要么被拒绝。在您的情况下,它们将被立即解析并推送到一个名为callback queue的队列中,当callstack为空时,将在该队列中拾取并执行它们

因此,当您的代码运行时,它会注册前两个,X和Y。它会将它们推送到基于FIFO的回调队列中,首先推送的内容都会首先执行

所以X开始执行,但是在X中有另一个承诺Z,所以它也被注册,并在队列中被推回Y。在它之后,一个被打印出来


现在,你的第二个承诺Y被执行,B被打印,最后Z被执行,C被打印。

为什么它是这样的顺序?承诺是异步的。代码不会坐在那里等待它们被执行,它只是存储它们并继续执行

你登记了两个THEN A和B。承诺完成了,他们被执行了。第一个运行A,它先注册另一个,然后注册C。第二个运行B,然后第三个运行C

var p=new Promiseresolve=>window.setTimeoutresolve,500 console.log'registinga' p、 函数{ console.log'C' p、 然后功能{ console.logC; }; console.logA; }; 控制台。记录“注册B” p、 然后功能{ console.logB; }; 该方法将一些代码设置为将来某个时刻执行的函数,当承诺得到解决时

A就是它的名字:当一个已经启动并异步运行的操作完成时,在将来某个时候可以使用的结果的承诺。启动异步操作并创建承诺的代码可以继续执行它必须执行的操作,而无需等待异步操作完成

每次调用。然后将一个函数添加到函数队列中,当承诺得到解决时,即异步操作成功完成时,将执行该函数。每个承诺都有自己的队列

您发布的顶级代码调用p,然后调用两次。执行后,p的队列包含以下等待执行的函数:

作用{ p、 然后功能{ console.logC; }; console.logA; } 作用{ console.logB; } 解析p后,它按顺序调用这两个函数。 第一个函数通过调用p向队列末尾的另一个函数发出调用,然后打印a。当它结束时,队列包含以下函数,等待调用:

作用{ console.logB; } 作用{ console.logC; } 显示的函数已从队列中删除,因为它已被执行


然后,这些函数按它们在队列中的顺序执行,当然,它们按此顺序打印B和C。它们中的每一个都会在执行后从队列中删除。

让我们逐行分解

// .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
@Bergi所说的异步调用被放置在调用堆栈中是正确的——这意味着js引擎将推进剩下的要执行的同步代码,然后返回调用堆栈

在您的示例中,当调用第一个async p.then时,它会跳转到下一个同步代码行,这恰好触发了第二个堆栈调用。当没有同步代码时,js引擎将查找堆栈中的第一个堆栈调用。它看到p.then,它触发第三个堆栈调用并移动到sync code console.logA;的下一个;。此时没有syn
留下c代码,因此引擎再次转到调用堆栈,并执行它看到的下一个堆栈调用和console.logB;同样,在没有同步代码的情况下,它进入调用堆栈,看到第三个堆栈调用并执行console.logC

,除了p是promisecode这一事实,对于p.then为什么会是nested@epascarello除了在B之后实现C的日志记录之外:-我可能误认为对于我的问题p中的代码是什么并不重要。在这种情况下,这并不重要,因为你在所有场合都使用相同的承诺。为什么会按这种顺序进行?因为你注册了两个thens A和B。承诺完成了,他们就被执行了。第一个运行A,它先注册另一个,然后注册C。第二个运行B,然后第三个运行C。