gpt4 book ai didi

javascript - 为什么用 p.then(resolve) 比用 resolve(p) 更早地解决新的 promise ?

转载 作者:行者123 更新时间:2023-12-03 07:18:35 26 4
gpt4 key购买 nike

Code#1 和 Code#2 的区别在于:Code#1 使用 resolve(p) 而 Code#2 使用 p.then(()=>resolve()) 。我希望输出序列是不变的,但它们会生成不同的序列。我不知道为什么。

代码 #1:resolve(p)

const p = Promise.resolve();

new Promise((resolve) => {
resolve(p); // <---
}).then(() => {
console.log('after:await');
});

p.then(() => console.log('tick:a'))
.then(() => console.log('tick:b'))
.then(() => console.log('tick:c'));

输出:

tick:a
tick:b
after:await
tick:c

代码 #2:p.then(()=>resolve())

const p = Promise.resolve();

new Promise((resolve) => {
p.then(()=>resolve()); // <---
}).then(() => {
console.log('after:await');
});

p.then(() => console.log('tick:a'))
.then(() => console.log('tick:b'))
.then(() => console.log('tick:c'));

输出:

tick:a
after:await
tick:b
tick:c

为什么输出顺序不同?

最佳答案

这实际上是一个非常有趣的问题,因为 Promise/A+ specs将允许第一个代码版本产生与代码的第二个版本相同的输出。

人们可以忽略这个问题,即 Promise 实现没有说明 resolve(p) 将如何实现。在查看 Promise/A+ 规范时,这是一个真实的陈述,引自其前言:

the core Promises/A+ specification does not deal with how to create, fulfill, or reject promises, ...

但是 Promise 的 EcmaScript 规范(第 25.4 节)比 Promise/A+ 规范要详细得多,并且要求将“作业”添加到相关作业队列的后面——对于 promise 结算来说,< em>PromiseJobs 队列(25.4.1.3.28.4 ):这决定了具体的顺序:

Required Job Queues

[...]
PromiseJobs: Jobs that are responses to the settlement of a Promise

[...]

The PendingJob records from a single Job Queue are always initiated in FIFO order

它还定义了 resolve(p) -- 当 p 是 thenable 时 -- 将 首先 将一个作业放入队列中将执行 p.then 方法的必要内部调用。这不会立即完成。在 25.4.2.2 引用 EcmaScript 规范中的注释:

This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.

以下代码段中的输出顺序说明了此语句:

const p1 = Promise.resolve();

// Wrap the `p1.then` method, so we can log something to the console:
const origThen = p1.then;
p1.then = function(...args) {
console.log("The p1.then method is called asynchronously when triggered by resolve(p1)");
origThen.call(this, ...args);
};
const p2 = new Promise(resolve => {
resolve(p1);
console.log("Code that follows is executed synchronously, before p1.then is");
});

当我们使用 p1.then(resolve) 方法调用而不是 resolve(p1) 时,我们得到相反的顺序:

const p1 = Promise.resolve();

// Wrap the `p1.then` method, so we can log something to the console:
const origThen = p1.then;
p1.then = function(...args) {
console.log("The p1.then method is called synchronously now");
origThen.call(this, ...args);
};
const p2 = new Promise(resolve => {
p1.then(resolve);
console.log("Code that follows is executed synchronously, after p1.then is");
});

您的代码

以上内容确实解释了您获得的不同输出顺序。这是第一个代码版本如何对操作进行排序。首先让我稍微重写一下,以便大多数涉及的 Promise 都有一个名称:

const p1 = Promise.resolve();
const p2 = new Promise((resolve) => resolve(p1));
const p3 = p2.then(() => console.log('after:await'));
const p4 = p1.then(() => console.log('tick:a'));
const p5 = p4.then(() => console.log('tick:b'))
const p6 = p5.then(() => console.log('tick:c'));

现在,在主同步代码执行完成后,只有 p1 处于已解决状态,并且作业队列(微任务队列)中存在两个作业,其中一个是由于resolve(p1) 和第二个因为 p1.then:

  1. 根据25.4.2.2 ,p1then 方法被调用,传递与 p2 相关的内部 [[resolve]] 函数。 p1.then 内部知道 p1 已解析,并将另一个作业放入队列以实际解析 p2!

  2. 执行带有“tick:a”的回调,promise p4 被标记为已完成,在作业队列中添加一个新作业。队列中现在有 2 个新作业,按顺序处理:

  3. 执行步骤 1 中的作业:p2 现在已解决。这意味着一个新作业被排队以实际调用相应的 then 回调

  4. 执行第 2 步的作业:执行带有“tick:b”的回调

只有稍后在第 3 步中添加的作业才会执行,它会使用“after:await”调用回调。

所以,总而言之。在 EcmaScript 中,一个 resolve(p),其中 p 是一个 thenable,它涉及一个异步作业,它本身会触发另一个异步作业来通知完成。

then 回调,用于区分第二个代码版本,只需要 一个 异步作业即可被调用,因此它发生在 "tick:b 的输出之前”。

关于javascript - 为什么用 p.then(resolve) 比用 resolve(p) 更早地解决新的 promise ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54202637/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com