Ten*_*ang 6 javascript es6-promise
为什么承诺首先打印所有成功然后是拒绝后,即使我为其编写代码随机出现
var errors = 0;
var successes = 0;
var p1;
for (var i = 0; i < 10; i++) {
p1 = new Promise(function(resolve, reject) {
var num = Math.random();
if (num < .5) {
resolve(num);
} else {
reject(num)
}
});
p1.then(function success(res) {
successes++;
console.log("*Success:* " + res)
}).catch(function error(error) {
errors++
console.log("*Error:* " + error)
});
}Run Code Online (Sandbox Code Playgroud)
OUTPUT
VM331:16 *Success:* 0.28122982053146894
VM331:16 *Success:* 0.30950619874924445
VM331:16 *Success:* 0.4631742111936423
VM331:16 *Success:* 0.059198322061176256
VM331:16 *Success:* 0.17961879374514966
VM331:16 *Success:* 0.24027158041021068
VM331:19 *Error:* 0.9116586303879894
VM331:19 *Error:* 0.7676575145407345
VM331:19 *Error:* 0.5289135948801782
VM331:19 *Error:* 0.5581542856881132
Run Code Online (Sandbox Code Playgroud)
Jar*_*a X 12
它与异步代码的工作方式有关
.then().catch() - 必须等待队列两次(嗯,我需要解释一下)
.then() 只有一次
Promise本质上是异步的...在你的代码中,当一个promise解析时,.then代码放在microtask上?队列...并依次处理
当它拒绝,因为.then没有onRejected回调,那么,.catch你的情况下的promise链中的下一个处理程序是否被添加到微任务中?队列 - 但到那时,所有.then代码都已执行
尝试使用.then(onSuccess, onError),你会得到你期望的
var errors = 0;
var successes = 0;
var p1;
for (var i = 0; i < 10; i++) {
p1 = new Promise(function(resolve, reject) {
var num = Math.random();
if (num < .5) {
resolve(num);
} else {
reject(num);
}
});
p1.then(function success(res) {
successes++;
console.log("*Success:* " + res);
}, function error(error) {
errors++;
console.log("*Error:* " + error);
});
}Run Code Online (Sandbox Code Playgroud)
获得你想要的东西的另一种方式(至少在原生的Promises中)是
var errors = 0;
var successes = 0;
var p1;
for (let i = 0; i < 10; i++) {
p1 = new Promise(function(resolve, reject) {
setTimeout(() => {
var num = Math.random();
if (num < .5) {
resolve(`${i} ${num}`);
} else {
reject(`${i} ${num}`)
}
});
});
p1.then(function success(res) {
successes++;
console.log("*Success:* " + res)
}).catch(function error(error) {
errors++
console.log("* Error:* " + error)
});
}Run Code Online (Sandbox Code Playgroud)
这是因为setTimeout会延迟解析/拒绝
深入解释
首先要做的事情......你需要了解.then实际情况
.then(onFullfilled, onRejected)
Run Code Online (Sandbox Code Playgroud)
并返回一个Promise
接下来,.catch简直就是"语法糖"
.then(null, onRejected)
Run Code Online (Sandbox Code Playgroud)
实际上,在大多数Promise库中(在它们出生之前)它被定义为
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
};
Run Code Online (Sandbox Code Playgroud)
是的......所以让我们来看看你的代码的一个简单的简单版本 - 为了简洁,只使用三个承诺
function executorFunction(resolve, reject) {
const num = Math.random();
if (num < .5) {
resolve(num);
} else {
reject(num)
}
}
let successes = 0, errors = 0;
function success(res) {
successes++;
console.log("*Success:* " + res)
}
function error(error) {
errors++
console.log("*Error:* " + error)
}
const p1 = new Promise(executorFunction);
p1.then(success).catch(error);
const p2 = new Promise(executorFunction);
p2.then(success).catch(error);
const p3 = new Promise(executorFunction);
p3.then(success).catch(error);Run Code Online (Sandbox Code Playgroud)
您可以运行它并看到它产生相同的成功和错误顺序
现在,让我们稍微改变一下,这样我们总能获得成功/失败/成功
function executorFunction(num, fail) {
return (resolve, reject) => {
if (fail) {
reject(num);
} else {
resolve(num)
}
};
}
function success(res) {
console.log("*Success:* " + res)
}
function error(error) {
console.log("*Error:* " + error)
}
const p1 = new Promise(executorFunction(1, false));
p1.then(success).catch(error);
const p2 = new Promise(executorFunction(2, true));
p2.then(success).catch(error);
const p3 = new Promise(executorFunction(3, false));
p3.then(success).catch(error);Run Code Online (Sandbox Code Playgroud)
这总是输出
*Success:* 1
*Success:* 3
*Error:* 2
Run Code Online (Sandbox Code Playgroud)
所以我们看到你在问题中看到的顺序 - 到目前为止一切顺利
现在,让我们以扩展形式重写.then/.catch
function executorFunction(num, fail) {
return (resolve, reject) => {
if (fail) {
reject(num);
} else {
resolve(num)
}
};
}
function success(res) {
console.log("*Success:* " + res)
}
function error(error) {
console.log("*Error:* " + error)
}
const p1 = new Promise(executorFunction(1, true));
p1.then(success, null).then(null, error);
const p2 = new Promise(executorFunction(2, false));
p2.then(success, null).then(null, error);Run Code Online (Sandbox Code Playgroud)
让我们只使用两个承诺,第一个拒绝......我们知道这将输出success 2则error 1-即以相反的顺序,我们期待
那么让我们来分析一下发生了什么
因为您在Promise构造函数中同步解析/拒绝 executorFunction
const p1 = new Promise(executorFunction(1, false));
Run Code Online (Sandbox Code Playgroud)
是一个已经解决的Promise - 对于p2已经达到2,并且对于p1被拒绝,原因为1,但它永远不会处于Pending状态.所以,当一个承诺没有待处理(它已经解决,但这意味着要么已经完成或被拒绝,但是术语已经混淆了,所以我会继续说"没有待定"),任何"处理程序"都被添加到微任务队列 - 所以在所有代码的末尾,微任务队列看起来像
**microtask queue**
(resolved:2).then(success, null).then(null, error); // added second
(rejected:1).then(success, null).then(null, error); // added first
Run Code Online (Sandbox Code Playgroud)
现在JS引擎,因为没有任何运行,处理微任务队列(顺便说一下队列的头部在底部)
.then没有被拒绝的函数,所以承诺值带有链.then 以原始拒绝原因返回此被拒绝的承诺.
**microtask queue**
(rejected:1)>(rejected:1).then(null, error); // added third
(resolved:2).then(success, error).then(null, error); // added second
Run Code Online (Sandbox Code Playgroud)
现在处理下一个微任务
success success 2.then返回一个promise,因为你的success函数没有返回,这就是return undefined并且promise被解决为undefined.
**microtask queue**
(resolved:2)>(resolved:undefined).then(null, error); // added fourth
(rejected:1)>(rejected:1).then(null, error); // added third
Run Code Online (Sandbox Code Playgroud)
errorerror 1.then 返回一个promise,没有处理程序,因此没有任何东西被添加到microtask队列中.
**microtask queue**
(resolved:2)>(resolved:undefined).then(null, error); // added fourth
Run Code Online (Sandbox Code Playgroud)
现在处理下一个微任务
.then 返回一个promise,没有处理程序,因此没有任何东西被添加到microtask队列中.
**microtask queue**
**empty**
Run Code Online (Sandbox Code Playgroud)
为什么使用.then(onFullfilled,onRejected)会产生预期的顺序
好的,现在,如果我们编写代码
function executorFunction(num, fail) {
return (resolve, reject) => {
if (fail) {
reject(num);
} else {
resolve(num)
}
};
}
function success(res) {
console.log("*Success:* " + res)
}
function error(error) {
console.log("*Error:* " + error)
}
const p1 = new Promise(executorFunction(1, true));
p1.then(success, error);
const p2 = new Promise(executorFunction(2, false));
p2.then(success, error);Run Code Online (Sandbox Code Playgroud)
微任务队列开始,就像
**microtask queue**
(resolved:2).then(success, error); // added second
(rejected:1).then(success, error); // added first
Run Code Online (Sandbox Code Playgroud)
现在处理下一个微任务
error error 1.then 返回一个promise,没有处理程序,因此没有任何东西被添加到microtask队列中.
**microtask queue**
(resolved:2).then(success, error); // added second
Run Code Online (Sandbox Code Playgroud)
success success 2.then 返回一个promise,没有处理程序,因此没有任何东西被添加到microtask队列中.
**microtask queue**
**empty**
Run Code Online (Sandbox Code Playgroud)
为什么添加setTimeout会导致预期的顺序
现在让我们更改executorFunction以添加setTimeout
function executorFunction(num, fail) {
return (resolve, reject) => {
setTimeout(function() {
if (fail) {
reject(num);
} else {
resolve(num)
}
});
};
}
function success(res) {
console.log("*Success:* " + res)
}
function error(error) {
console.log("*Error:* " + error)
}
const p1 = new Promise(executorFunction(1, true));
p1.then(success, null).then(null, error);
const p2 = new Promise(executorFunction(2, false));
p2.then(success, null).then(null, error);Run Code Online (Sandbox Code Playgroud)
同样,为了简便起见,我们仅使用两个承诺,第一个失败了,因为我们知道,在原码输出会success 2那么fail 1
现在我们有两个队列考虑...... microtask和"计时器" -定时器队列中有比微任务队列更低的优先级...即,当没有运行(立即)时,JS将处理微任务队列,直到它为空,甚至在尝试计时器队列之前
所以 - 我们走了
在我们的代码结束时
** empty microtask queue ** timer queue
setTimeout(resolve(2))
setTimeout(reject(1))
Run Code Online (Sandbox Code Playgroud)
处理计时器队列,我们得到一个微任务 (rejected:1).then(success, null).then(null, error)
** microtask queue ** timer queue
(rejected:1).then(success, null).then(null, error) setTimeout(resolve(2))
Run Code Online (Sandbox Code Playgroud)
哦,微任务队列中有一些东西,让我们处理它并忽略定时器队列
.then没有被拒绝的函数,所以承诺值带有链.then 以原始拒绝原因返回此被拒绝的承诺哦,微任务队列中有一些东西,让我们处理它并忽略定时器队列
** microtask queue ** timer queue
(rejected:1).then(success, null).then(null, error) setTimeout(resolve(2))
Run Code Online (Sandbox Code Playgroud)
errorerror 1.then 返回一个promise,没有处理程序,因此没有任何东西被添加到microtask队列中现在队列看起来像
** microtask queue ** timer queue
setTimeout(resolve(2))
Run Code Online (Sandbox Code Playgroud)
因此,我不需要继续,因为error 1在第二个承诺链开始之前已经输出了:p1
| 归档时间: |
|
| 查看次数: |
713 次 |
| 最近记录: |