我在HTML文件中包含以下代码:
const fooBar = function(resolve, reject) {
let flag = (Math.round(Math.random() * 10) % 2);
if(flag)
resolve({ "value": "foo", "rand": Math.random() });
else
reject({ "value": "bar", "rand": Math.random() });
};
const fooBarSuccess1 = function(value) {
console.log("Success 1:" + JSON.stringify(value));
};
const fooBarFailure1 = function(value) {
console.log("Failure 1:" + JSON.stringify(value));
};
const fooBarSuccess2 = function(value) {
console.log("Success 2:" + JSON.stringify(value));
};
const fooBarFailure2 = function(value) {
console.log("Failure 2:" + JSON.stringify(value));
};
new Promise(fooBar).then(fooBarSuccess1).catch(fooBarFailure1);
new Promise(fooBar).then(fooBarSuccess2, fooBarFailure2);
console.log("Before setting MicroTask.");
setTimeout(() => console.log("This Timeout was set before the MicroTask!"));
queueMicrotask(() => console.log("From MicroTask!"));
console.log("After setting MicroTask.");
当Promise被拒绝时,fooBarFailure1
在微任务队列的末尾执行,因此您可能会获得以下输出:
Before setting MicroTask. After setting MicroTask. Success 2:{"value":"foo","rand":0.3675094508130746} From MicroTask! Failure 1:{"value":"bar","rand":0.6828171208953322} This Timeout was set before the MicroTask!
但是,不应该在执行queueMicrotask
中的代码之前调用它吗?而且我看不到fooBarFailure2
有任何此类问题。它按预期顺序执行。结果与Firefox 71和Google Chrome 78相同。有人可以解释这里发生了什么吗?
答案 0 :(得分:4)
区别在于fooBarFailure1
与根承诺(来自new Promise
的承诺)比fooBarFailure2
更远。 fooBarFailure1
未连接到根承诺,而是连接到.then(fooBarSuccess1)
创建的根承诺:
new Promise(fooBar).then(fooBarSuccess1).catch(fooBarFailure1);
相反,fooBarSuccess2
和fooBarFailure2
被两者附加到根目录诺言:
new Promise(fooBar).then(fooBarSuccess2, fooBarFailure2);
在fooBarFailure1
之前的链中有一个内部拒绝处理程序,但是fooBarFailure2
是直接挂钩的。这就是导致额外的异步“滴答声”的原因。
让我们看一下故障示例,因为它简化了事情:
const success = function(value) {
console.log("This never happens");
};
const fooBarFailure1 = function(value) {
console.log("Failure 1");
};
const fooBarFailure2 = function(value) {
console.log("Failure 2");
};
Promise.reject().then(success).catch(fooBarFailure1);
Promise.reject().then(success, fooBarFailure2);
console.log("Before setting MicroTask.");
setTimeout(() => console.log("This Timeout was set before the MicroTask!"));
queueMicrotask(() => console.log("From MicroTask!"));
console.log("After setting MicroTask.");
其输出是:
Before setting MicroTask. After setting MicroTask. Failure 2 From MicroTask! Failure 1 This Timeout was set before the MicroTask!
这是为什么:
Promise.reject()
在两种情况下均返回被拒绝的承诺。Promise.reject().then(success).catch(fooBarFailure1);
中
.then(success)
创建一个新的Promise,并挂接实现和拒绝处理程序;拒绝处理程序是内部的,只是传递了拒绝原因,因为没有提供拒绝处理程序。.catch(fooBarFailure1)
在then
的承诺上挂钩了拒绝处理程序。Promise.reject().then(success, fooBarFailure2);
中:
then
将履行处理程序(success
)和拒绝处理程序(fooBarFailure2
)挂钩到Promise.reject()
的承诺"Before setting MicroTask."
已记录。setTimeout
将其任务排队queueMicrotask
将其微任务排入队列"After setting MicroTask."
已记录。Promise.reject().then(success).catch(fooBarFailure1);
的拒绝:它拒绝then
创建的诺言,排队一个微任务以对返回的诺言then
调用拒绝处理程序。Promise.reject().then(success, fooBarFailure2);
的拒绝:那拒绝承诺,调用fooBarFailure2
。
"Failure 2"
已记录。queueMicrotask
的任务。
"From MicroTask!"
已记录。fooBarFailure1
的微任务调用运行。
"Failure 1"
已记录。"This Timeout was set before the MicroTask!"
已记录。