- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Code#1 和 Code#2 的区别在于:Code#1 使用 resolve(p)
而 Code#2 使用 p.then(()=>resolve())
。我希望输出序列是不变的,但它们会生成不同的序列。我不知道为什么。
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
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.2 和 8.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
:
根据25.4.2.2 ,p1
的 then
方法被调用,传递与 p2
相关的内部 [[resolve]]
函数。 p1.then
内部知道 p1
已解析,并将另一个作业放入队列以实际解析 p2
!
执行带有“tick:a”的回调,promise p4 被标记为已完成,在作业队列中添加一个新作业。队列中现在有 2 个新作业,按顺序处理:
执行步骤 1 中的作业:p2 现在已解决。这意味着一个新作业被排队以实际调用相应的 then
回调
执行第 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/
我安装了 fakeLoader (jquery 预加载器)但我无法在页面加载前显示它。 在 mozilla 中它几乎可以正常工作(奇怪的是......),但在 Chrome 和 Opera 中,页面首
我试图通过以下代码在触摸事件上移动 ImageView: public class ScrollableImageView extends ImageView { private Gestur
我是一名优秀的程序员,十分优秀!