JavaScript承诺中的排序
我偶然发现了JavaScript中与承诺相关的代码示例,不明白为什么它会键入ABC而不是CAB。 代码如下: p、 然后功能{ p、 然后功能{ console.logC; }; console.logA; }; p、 然后功能{ console.logB; }; // A、B、CJavaScript承诺中的排序,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); 这是异步代码的预期行为,
我可能错误地认为,对于我的问题,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。