我最近在 Stack Overflow 上遇到了这个问题,询问 then 方法在 JavaScript 中是如何工作的。响应者 Trincot 发表了以下评论:
主机将检查哪些作业队列有条目,优先考虑高优先级的作业队列。Promise 作业队列具有非常高的优先级,通常高于处理用户交互或其他外部事件的事件队列。因此,上面第 4 步放入队列的作业将从 Promise Job 队列中取出。该作业将顺序调用 myPromise 对象上已注册为 then 回调的回调函数(例如在步骤 7 中注册的回调函数)。
如果我正确理解他的解释,每当调用resolve函数时,JavaScript都会在作业队列中安排一个微任务(或一个作业),当调用堆栈为空时,它将执行传递给then的所有回调,包括链接。例如:
Promise.resolve("Hi")
.then(() => {
console.log("Hi");
})
.then(() => {
console.log("World");
});
在这种情况下,承诺会立即解决,这意味着将立即安排微任务。当 then 回调完成执行时,JS 引擎将检查队列中是否有微任务。由于 Promise 立即得到解决,因此它将执行微任务,微任务又执行传递给 then 方法的所有处理程序。结果,代码将输出“Hi”和“World”。
但是,为什么这段代码输出“1 3 2 4”而不是“1 2 3 4”呢?
const p1 = Promise.resolve();
const p2 = Promise.resolve();
p1.then(() => {
console.log(1);
}).then(() => {
console.log(2);
});
p2.then(() => {
console.log(3);
}).then(() => {
console.log(4);
});
我相信代码应该输出“1 2 3 4”而不是“1 3 2 4”。这是因为,当 p1 和 p2 解析时,两个微任务会排队。当 then 回调完成执行时,它们将这些回调添加到其内部列表中。一旦调用堆栈为空,JS 引擎就会从队列中选择最旧的任务并执行它。此任务应执行传递给该特定 Promise 实例的所有 then 处理程序。然而,事情似乎并没有按预期发生。有人可以向我解释这种行为背后的原因吗?
感谢您抽出宝贵的时间,祝您有美好的一天!
这是一个误解。微任务(承诺作业)在以下情况下排队:
then
在已解决的 Promise 上执行then
一个 Promise 被解析,并且在它解析之前已经执行了一个方法:对于每个这样的then
回调,都会创建一个单独的作业。因此,当前两条语句执行完毕后,promise 作业队列中还没有添加任何内容。
意识到:
then
它的回调才会被放入 Promise 作业队列中。否则它会被注册以等待承诺解决。then
处于挂起状态的 Promise ,即使是在已解决的 Promise 上调用它时也是如此。它可能有助于识别
then()
变量调用返回的承诺,并命名回调函数。这将使你的脚本看起来像这样:
以下是该脚本中发生的情况的简化视图:
?
表示它正在等待;F
意味着它已实现。p1 = Promise.resolve()
p2 = Promise.resolve()
q1 = p1.then(p1_then)
p1_then
r1 = q1.then(q1_then)
p1_then
q2 = p2.then(p2_then)
p1_then
,p2_then
r2 = q2.then(q2_then)
p1_then
,p2_then
p1_then
p2_then
p1_then
console.log(1)
p2_then
p1_then
p2_then
,q1_then
p2_then
q1_then
p2_then
console.log(3)
q1_then
p2_then
q1_then
,q2_then
q1_then
q2_then
q1_then
console.log(2)
q2_then
q1_then
q2_then
q2_then
q2_then
console.log(4)
q2_then
这是执行顺序:
所以过程的顺序将是1,3,2,4
请记住,虽然代码看起来是同步的,但 Promise 解析和 .then() 处理程序的执行是异步过程。