2 回答
TA贡献1799条经验 获得超9个赞
这是一个很酷的问题,需要深入探究。
当你这样做时:
verifier(3,4).then(...)
返回一个新的承诺,在新拒绝的承诺可以运行后面的处理程序之前,需要另一个循环回到事件循环.catch()。这个额外的循环给出了下一个序列:
verifier(5,4).then(...)
有机会.then()在上一行之前运行它的处理程序,因为在第一个处理程序进入队列.catch()之前它已经在队列中,并且项目以 FIFO 顺序从队列中运行。.catch()
请注意,如果您使用.then(f1, f2)form 代替.then().catch(),它会在您期望的时候运行,因为没有额外的承诺,因此不涉及额外的滴答:
const verifier = (a, b) =>
new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));
verifier(3, 4)
.then((response) => console.log("response (3,4): ", response),
(error) => console.log("error (3,4): ", error)
);
verifier(5, 4)
.then((response) => console.log("response (5,4): ", response))
.catch((error) => console.log("error (5,4): ", error));
请注意,我还标记了所有消息,这样您就可以看到verifier()
它们来自哪个调用,从而更容易阅读输出。
ES6 Spec on promise 回调排序和更详细的解释
.then()
ES6 规范告诉我们,promise“作业”(因为它调用 a或 的回调.catch()
)根据它们被插入作业队列的时间以 FIFO 顺序运行。它没有具体命名 FIFO,但它指定新作业插入队列末尾,作业从队列开头运行。这实现了 FIFO 排序。
PerformPromiseThen(执行来自 的回调.then()
)将导致EnqueueJob,这是解决或拒绝处理程序被安排实际运行的方式。EnqueueJob 指定将挂起的作业添加到作业队列的后面。然后NextJob操作从队列的前面拉出项目。这确保了 Promise 作业队列中服务作业的 FIFO 顺序。
因此,在原始问题的示例中,我们获得了verifier(3,4)
promise 的回调和按verifier(5,4)
运行顺序插入作业队列的 promise,因为这两个原始 promise 都已完成。然后,当解释器返回到事件循环时,它首先开始执行verifier(3,4)
任务。该承诺被拒绝,并且在verifier(3,4).then(...)
. 因此,它所做的是拒绝verifier(3,4).then(...)
返回的承诺,并导致将verifier(3,4).then(...).catch(...)
处理程序插入到 jobQueue 中。
然后,它返回到事件循环,它从 jobQueue 中提取的下一个作业就是作业verifier(5, 4)
。它有一个已解决的承诺和一个解决处理程序,因此它调用该处理程序。这会导致response (5,4):
显示输出。
然后,它返回到事件循环,它从 jobQueue 中提取的下一个作业是verifier(3,4).then(...).catch(...)
它运行该作业的作业,这会导致显示error (3,4)
输出。
这是因为.catch()
第一个链中的承诺级别在其链中比.then()
第二个链中的承诺级别更深,这导致了您报告的排序。而且,这是因为 promise 链是通过作业队列以 FIFO 顺序从一个级别遍历到下一个级别,而不是同步的。
关于依赖此级别的调度详细信息的一般建议
仅供参考,一般来说,我尝试编写不依赖于这种详细时序知识的代码。虽然它很好奇并且有时对理解很有用,但它是脆弱的代码,因为对代码进行看似无害的简单更改可能会导致相对时序发生变化。因此,如果像这样的两条链之间的时序至关重要,那么我宁愿以一种强制按照我想要的方式进行时序的方式编写代码,而不是依赖于这种详细的理解水平。
TA贡献1779条经验 获得超6个赞
Promise.resolve()
.then(() => console.log('a1'))
.then(() => console.log('a2'))
.then(() => console.log('a3'))
Promise.resolve()
.then(() => console.log('b1'))
.then(() => console.log('b2'))
.then(() => console.log('b3'))
由于相同的原因,您将看到 a1、b1、a2、b2、a3、b3 而不是输出 a1、a2、a3、b1、b2、b3 - 每个 then 都会返回一个 promise 并且它会进入事件循环的末尾队列。所以我们可以看到这个“无极跑”。当有一些嵌套的承诺时也是如此。
添加回答
举报