有许多关于如何在使用JavaScript Promise编程时使用“然后”和“捕获”的教程。然而,所有这些教程似乎都忽略了一个重要的点:从然后/捕获块返回以打破promise链。让我们从一些同步代码开始来说明这个问题:
try {
someFunction();
} catch (err) {
if (!(err instanceof MyCustomError))
return -1;
}
someOtherFunction();
本质上,我正在测试一个捕获的错误,如果不是我期望的错误,我会返回给调用方,否则程序将继续。然而,这种逻辑在Promise中不起作用:
Promise.resolve(someFunction).then(function() {
console.log('someFunction should throw error');
return -2;
}).catch(function(err) {
if (err instanceof MyCustomError) {
return -1;
}
}).then(someOtherFunction);
这种逻辑用于我的一些单元测试,我希望函数以某种方式失败。即使我将catch更改为then块,我仍然无法打破一系列链式promise,因为从then/catch块返回的任何内容都将成为沿链传播的promise。
我想知道Promise是否能够实现这个逻辑;如果没有,为什么?对我来说很奇怪,promise链永远不会被打破。谢谢!
编辑于08/16/2015:根据到目前为止给出的答案,被拒绝的promise返回的然后块将通过promise链传播,并跳过所有后续的然后块,直到被捕获(处理)。这种行为很好理解,因为它简单地模拟了以下同步代码(方法1):
try {
Function1();
Function2();
Function3();
Function4();
} catch (err) {
// Assuming this err is thrown in Function1; Function2, Function3 and Function4 will not be executed
console.log(err);
}
但是,我要问的是同步代码中的以下场景(方法2):
try {
Function1();
} catch(err) {
console.log(err); // Function1's error
return -1; // return immediately
}
try {
Function2();
} catch(err) {
console.log(err);
}
try {
Function3();
} catch(err) {
console.log(err);
}
try {
Function4();
} catch(err) {
console.log(err);
}
我想以不同的方式处理不同功能中出现的错误。我可能在一个catch块中捕获所有错误,如方法1所示。但是那样的话,我必须在catch块中做一个大的switch语句来区分不同的错误;此外,如果不同函数抛出的错误没有公共的switchable属性,那么我将根本无法使用switch语句;在这种情况下,我必须为每个函数调用使用单独的try/catch块。方法2有时是唯一的选择。Promise的then/catch语句不支持这种方法吗?
没有内置的功能可以根据您的请求跳过整个剩余链。但是,您可以通过在每个捕获中抛出特定错误来模拟此行为:
doSomething()
.then(func1).catch(handleError)
.then(func2).catch(handleError)
.then(func3).catch(handleError);
function handleError(reason) {
if (reason instanceof criticalError) {
throw reason;
}
console.info(reason);
}
如果任何捕获块捕获了CrialError
,它们将直接跳到末尾并抛出错误。任何其他错误都将被控制台记录下来,然后继续到下一个。然后
块。
首先,我在这段代码中看到了一个常见错误,可能会让您完全困惑。这是您的示例代码块:
Promise.resolve(someFunction()).then(function() {
console.log('someFunction should throw error');
return -2;
}).catch(function(err) {
if (err instanceof MyCustomError) {
return -1;
}
}).then(someOtherFunction()); // <== Issue here
您需要将函数引用传递给。然后()
handler,而不是实际调用函数并传递其返回结果。因此,上述代码可能是:
Promise.resolve(someFunction()).then(function() {
console.log('someFunction should throw error');
return -2;
}).catch(function(err) {
if (err instanceof MyCustomError) {
// returning a normal value here will take care of the rejection
// and continue subsequent processing
return -1;
}
}).then(someOtherFunction); // just pass function reference here
请注意,我在中的函数之后删除了
handler,因此您只是传递函数引用,而不是立即调用函数。这将允许promise基础设施决定是否在将来调用promise。如果你犯了这个错误,它将完全抛弃你的promise是如何运作的,因为事情将被称为无论如何。()
。然后()
关于捕捉拒绝的三个简单规则。
您可以在这个JSFIDLE中看到几个示例,其中显示了三种情况:
>
从拒绝处理程序返回常规值会导致下一个。然后()
解析要调用的处理程序(例如,继续正常处理),
抛出拒绝处理程序会导致正常的解析处理停止,并跳过所有解析处理程序,直到到达拒绝处理程序或链的末尾。如果在解析处理程序中发现意外错误,这是停止链的有效方法(我认为这是您的问题)。
不存在拒绝处理程序会导致正常的解析处理停止,并跳过所有解析处理程序,直到到达拒绝处理程序或链的末尾。
这是用语言的特性无法实现的。但是,基于模式的解决方案是可用的。
这里有两个解决方案。
重新抛出之前的错误
这种模式基本上是合理的。。。
Promise.resolve()
.then(Function1).catch(errorHandler1)
.then(Function2).catch(errorHandler2)
.then(Function3).catch(errorHandler3)
.then(Function4).catch(errorHandler4)
.catch(finalErrorHandler);
Promise.resolve()
不是严格必需的,但允许所有. so(). cat()
行具有相同的模式,并且整个表达式更容易理解。
... 但是:
除非编写错误处理程序,使其能够区分先前抛出的错误和新抛出的错误,否则不会发生所需的链外跳转。例如:
function errorHandler1(error) {
if (error instanceof MyCustomError) { // <<<<<<< test for previously thrown error
throw error;
} else {
// do errorHandler1 stuff then
// return a result or
// throw new MyCustomError() or
// throw new Error(), new RangeError() etc. or some other type of custom error.
}
}
现在:
if(MyCustomError的错误实例)
协议的错误处理程序捕获。> 如果您需要灵活地跳到链的末尾或不跳到链的末尾,此模式将非常有用,具体取决于抛出的错误类型。我认为这是罕见的情况。
演示
绝缘捕捉器
另一个解决方案是引入一种机制来保持每个。catch(errorHandlerN)
“隔离”,这样它将只捕获由其相应的功能n
引起的错误,而不是任何先前的错误。
这可以通过在主链中只有成功处理程序来实现,每个成功处理程序包含一个包含子链的匿名函数。
Promise.resolve()
.then(function() { return Function1().catch(errorHandler1); })
.then(function() { return Function2().catch(errorHandler2); })
.then(function() { return Function3().catch(errorHandler3); })
.then(function() { return Function4().catch(errorHandler4); })
.catch(finalErrorHandler);
这里promise。resolve()
起着重要作用。没有它,Function1()。catch(errorHandler1)
将位于主链中catch()
不会与主链隔离。
现在
如果您想总是跳到链的末尾,无论抛出的错误类型如何,请使用此模式。不需要自定义错误构造函数,也不需要以特殊方式编写错误处理程序。
演示
用例
选择哪种模式将取决于已经给出的考虑因素,也可能取决于项目团队的性质。
在 中,尝试捕获最终阻止的工作原理是什么? 所以如果有例外,我知道它会跳到捕获块,然后跳到最后的块。 但是如果没有错误,catch块不会运行,但是finally块会运行吗?
我试图拦截来自所有promise然后方法的响应。但是我不能在原型然后方法中得到响应数据。请找到下面的代码。 在上面的代码中,我可以看到控制台打印在所有Promise调用中。但是我无法在then中获得响应对象。 控制台中打印的this对象值: “then”原型方法中的打印参数: 请建议我在then方法中获取所有promise方法的响应对象。 我尝试使用“arguments[0].arguments”
我使用的是交互式代理的ibapi,我通常被困在如何捕获返回的数据上。例如,根据api文档,当我请求reqAccountSummary()时,该方法通过accountSummary()传递数据。但他们的例子只打印数据。我曾尝试捕获数据或将其分配给变量,但他们的文档中没有任何地方显示如何执行此操作。我也在谷歌搜索,只找到register()和registerAll(),但这是来自ib.opt的,它不在
问题内容: 我需要兑现承诺,以便可以通过封闭函数将其返回。我知道,由于正常的JavaScript范围,我可能无法按照编码的方式进行操作。有什么办法可以做到吗? 位于#1 的 console.log 会生成正确的数据。 console.log #2总是产生’a’; 任何指针将不胜感激。 问题答案: 许诺背后的基本原则之一是它是异步处理的。这意味着您无法创建承诺,然后立即在代码中同步使用其结果(例如,
我正在努力理解如何在Javascript中获得一个承诺的值,以便能够检查它是真的还是假的。 如果我console.log有效变量,它将返回以下内容: 在我的if语句中,我试图检查允诺值是否为真,但我不知道如何访问该值:/谁能告诉我如何检查该值吗? 谢谢
原文是这样的: 这确实令人惊讶,但最终明白了(嗯,至少我想我明白了)为什么会这样发生。 现在,我将第二个更改为: 如果我遗漏了一些明显的东西,或者我的问题是愚蠢的,让我提前说声对不起。还有谢谢你!