我从 E6 Promises 开始。我非常喜欢它们,但有一个关于错误处理的关键概念我不明白,希望得到一些澄清。
让我们假设以下返回 promise 的简单函数:
function promiseString(str, timeout, doResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (doResolve) {
resolve(str);
} else {
reject(new Error("Rejecting " + str));
}
}, timeout);
});
}
它非常简单,只是为传递给它的字符串返回一个 promise ,并导致该 promise 在“超时”毫秒内被解决或拒绝(基于第三个参数)。
我可以按预期完全使用它,如下所示:
promiseString("One", 100, true)
.then((str) => { console.log("First then is " + str); return promiseString(str + " two", 100, true); })
.then((str) => { console.log("Second then is " + str); return promiseString(str + " three", 100, true); })
.then((str) => console.log(str))
.catch((err) => console.error(err));
如果在此链中的任何调用中将第三个参数从“true”更改为“false”,我的错误将按预期捕获并发送到 console.error()。
但是,现在想象以下(同样愚蠢的)函数来构造一个有前途的对象:
function DoublePromiser(str1, str2, doResolve) {
this.promise = new Promise((resolve, reject) => {
promiseString(str1, 100, doResolve)
.then((s1) => promiseString(s1 + str2, 100, doResolve))
.then((s2) => resolve(s2));
});
}
想象一下,现在我按如下方式使用这段代码,所有内容都解析,没有任何内容拒绝,(doResolve 设置为 true):
var dp = new DoublePromiser("Big", "Promise", true);
dp.promise
.then((s) => console.log("DoublePromise: " + s))
.catch((err)=>console.log("I did catch: ", err.message));
正如预期的那样,我在控制台中看到以下内容:
DoublePromise: BigPromise
但是,现在我更改了消费代码,将 doResolve 设置为“false”(这导致我的 promise 例程被拒绝):
var dp = new DoublePromiser("Big", "Promise", false);
dp.promise
.then((s) => console.log("DoublePromise: " + s))
.catch((err)=>console.log("I did catch: ", err.message));
由于我对错误应该如何“冒泡”的理解,我希望控制台记录如下:
I did catch: Rejecting Big
但事实并非如此。相反,控制台显示 Uncaught Error :
Uncaught (in promise) Error: Rejecting Big
如果我在 DoublePromiser 中的链的末尾添加一个 catch,我只会得到我期望(和想要)的东西,如下所示:
function DoublePromiser(str1, str2, doResolve) {
this.promise = new Promise((resolve, reject) => {
promiseString(str1, 100, doResolve)
.then((s1) => promiseString(s1 + str2, 100, doResolve))
.then((s2) => resolve(s2))
.catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK
});
}
现在我得到了我所期望的,错误并没有被捕获。但这似乎与错误冒泡的整个想法背道而驰,而且捕获错误只是为了重新拒绝相同的错误似乎很奇怪。
我是不是缺少一种让它简单工作的方法?
我是否遗漏了一些基本概念?
最佳答案
您正在使用 promise 构造函数反模式。不要将现有的 promise 包装在您自己做出的另一个 promise 中,因为这只会让您做很多额外的工作以使事情正常工作,而且由于大多数人没有正确地做这些额外的工作,它也很容易出现编程错误。只需返回您已经拥有的 promise 即可。
改变这个:
function DoublePromiser(str1, str2, doResolve) {
this.promise = new Promise((resolve, reject) => {
promiseString(str1, 100, doResolve)
.then((s1) => promiseString(s1 + str2, 100, doResolve))
.then((s2) => resolve(s2))
.catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK
});
}
为此:
function DoublePromiser(str1, str2, doResolve) {
return promiseString(str1, 100, doResolve)
.then((s1) => promiseString(s1 + str2, 100, doResolve));
}
然后将其作为函数使用:
DoublePromiser("Big", "Promise", false).then(...);
回顾:您几乎总是希望从 .then()
处理程序中返回内部 promise ,因为这允许嵌套错误向上传播,并且还可以适本地链接/排序异步操作.
而且,您几乎总是希望避免围绕现有 promise 包装新 promise ,因为您可以链接和/或返回您已有的现有 promise 。
此外,请注意,如果您执行 .catch()
,它将“处理”一个被拒绝的 promise 并返回一个新的未被拒绝的 promise ,从那里继续 promise 链,除非在.catch()
处理程序返回一个被拒绝的 promise 或抛出一个异常。所以,这:
p.catch((err) => console.log(err)).then(() => console.log("chain continues"))
将愉快地执行两个 console.log()
语句,因为 .catch()
“处理”了 promise ,因此 promise 链愉快地继续。
正如我在之前的评论中所说,如果没有 20 页的关于 promises 如何工作的教程,这些 100% 的理论讨论很难准确地达到您真正想要完成的目标(我们必须猜测真正的问题是什么)很多东西。如果您发布一个您尝试使用此技术解决的真实问题,那就更好了,我们可以通过几行代码和几段解释来展示/解释最好的方法。
关于javascript - ES6 Promise 错误没有按预期冒泡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38625209/