背景
我正在使用 Promises,我有许多函数可能返回也可能不返回 Promise,也可能失败也可能不失败,如下例所示:
//does not return a Promise, simply a string
let goodFun = function(){
return "I like bananas!";
};
//blows up!
let badFun = function(){
throw "A general error blaahh!";
};
//You get the point ...
由于这些函数可能会或可能不会返回 Promises 并且可能会或可能不会失败,因此我需要等待它们全部执行。为了实现这一点,我有一个函数来调用它们并等待它们的执行:
let asyncFun = function(){
return Promise.all([badFun(), goodFun()]);
};
问题
到目前为止一切顺利。我的代码调用了 asyncFun
,我预计它的一些函数实际上会失败。为了做好准备,我添加了一个陷阱:
let executor = function(){
let numbsArray = [1, 2, 3];
let respArray = [];
for(let num of numbsArray){
respArray.push(
asyncFun()
.catch( error => console.log(`I failed with ${error} and ${num}`))
);
}
return Promise.all(respArray);
};
问题是 catch
根本没有捕捉到任何东西!
即使在调用 executor
的函数中添加一个 catch 也没有捕获到任何东西!
executor()
.catch(error => console.log("Failed miserably to catch error!"));
研究
我真的不明白为什么我的 catch 子句没有捕捉到异常。为了找出答案,我阅读了这个讨论:
这让我相信我的所有函数 goodFun
和 badFun
无论如何都必须始终返回一个 promise 。
这让我感到困惑,因为根据 MDN documentation该数组可能包含一个 Promise,或一个 Promise 的结果(如字符串或数字)。
我还想避免在我的函数中添加甚至更多样板代码....
问题:
- 我如何修复我的代码,以便捕获可以添加最少的代码或样板代码?
代码
let goodFun = function() {
return "I like bananas!";
};
let badFun = function() {
throw "A general error blaahh!";
};
let asyncFun = function() {
return Promise.all([badFun(), goodFun()]);
};
let executor = function() {
let numbsArray = [1, 2, 3];
let respArray = [];
for (let num of numbsArray) {
respArray.push(
asyncFun()
.catch(error => console.log(`I failed with ${error} and ${num}`))
);
}
return Promise.all(respArray);
};
executor()
.catch(error => console.log("Failed miserably to catch error!"));
最佳答案
.catch
es 不工作的原因是错误被同步抛出。代码执行甚至不会执行 .catch() 指令来设置 catch 处理程序,因为错误已经抛出并且代码执行已转到其他地方。如果您将所有内容都包装在一个普通的 try-catch
中,我想您会看到它捕获了您抛出的错误。
例子:
let goodFun = function() {
return "I like bananas!";
};
//blows up!
let badFun = function() {
throw "A general error blaahh!";
};
try {
Promise.all([goodFun(), badFun()])
.then(results => console.log(results))
.catch(error => console.error(error))
} catch (e) {
console.error("Wups, I caught an error. This wasn't supposed to happen.", e);
}
This is confusing for me, because according to the MDN documentation the array may contain a Promise, or a result from one (like a string, or a number).
MDN 文档绝对正确,但是如果 badFun()
抛出错误,Promise.all
对此无能为力,因为程序流程将沿着调用堆栈向下寻找可以捕获抛出的错误的东西。
如果您不确定某些代码是同步的还是基于 promise 的(或者它是否会抛出同步错误),您可以使用它来安全地包装一个 promise:
function executeSafe(action) {
return Promise.resolve().then(action);
}
这将保护 action() 免受任何发生的“繁荣”的影响。
例子:
let executeSafe =
action => Promise.resolve().then(action);
let goodFun =
() => "I like bananas!";
//blows up!
let badFun =
() => { throw "A general error blaahh!" };
Promise.all([goodFun, badFun].map(executeSafe))
.then(results => console.log(results))
.catch(error => console.error(error))
仅供引用,如果您使用的是 Bluebird,那么它有一个内置方法 Promise.try
,其目的与上面的 executeSafe
相同: Promise.all([goodFun, badFun].map(Promise.try))
.
这是您的完整示例并进行了必要的修改:
let executeSafe =
action => Promise.resolve().then(action);
let goodFun =
() => "I like bananas!";
//blows up!
let badFun =
() => {
throw "A general error blaahh!"
};
let asyncFun =
() => Promise.all([goodFun, badFun].map(executeSafe));
let executor = function() {
let numbsArray = [1, 2, 3];
return Promise.all(numbsArray.map(num =>
asyncFun()
.catch(error => console.log(`I failed with ${error} and ${num}`))
));
}
executor();
这里是 executor
之外的 .catch
:
let executeSafe =
action => Promise.resolve().then(action);
let goodFun =
() => "I like bananas!";
//blows up!
let badFun =
() => {
throw "A general error blaahh!"
};
let asyncFun =
() => Promise.all([goodFun, badFun].map(executeSafe));
let executor = function() {
let numbsArray = [1, 2, 3];
return Promise.all(numbsArray.map(asyncFun));
}
executor().catch(error => console.error("Miserably failed to catch anything.", error));
关于javascript - 当错误可能未包含在 promise 中时,我如何使用 promise 来捕获错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42808381/