在下面的代码中,promise的$q catch函数捕获了一个异常:
// Fiddle - http://jsfiddle.net/EFpn8/6/
f1().then(function(data) {
console.log("success 1: "+data)
return f2();
})
.then(function(data) {console.log("success 2: "+data)})
.catch(function(data) {console.log("error: "+data)});
function f1() {
var deferred = $q.defer();
// An exception thrown here is not caught in catch
// throw "err";
deferred.resolve("done f1");
return deferred.promise;
}
function f2() {
var deferred = $q.defer();
// An exception thrown here is handled properly
throw "err";
deferred.resolve("done f2");
return deferred.promise;
}
但是,当我查看控制台日志输出时,我看到了以下内容:
异常是在Angular中捕获的,但也是由浏览器的错误处理捕获的。这种行为在Q库中也会重现。
这是个bug吗?如何才能真正捕获$q的异常?
发布于 2017-02-15 21:31:08
已在AngularJS 1.6版中修复
这种行为的原因是,未捕获的错误与常规拒绝不同,例如,它可能是由编程错误引起的。在实践中,这对用户来说是令人困惑或不受欢迎的,因为本机promise和任何其他流行的promise库都不能区分抛出的错误和常规的拒绝。(注意:虽然此行为不违反Promises/A+规范,但也没有规定。)
$q:
由于e13eea,从promise的onFulfilled
或onRejection
处理程序抛出的错误与常规拒绝完全相同。以前,它也会被传递给$exceptionHandler()
(除了以错误为理由拒绝承诺之外)。
新的行为适用于所有依赖于$q
的服务/控制器/过滤器等(包括内置服务,如$http
和$route
)。例如,如果抛出错误,$http's transformRequest/Response
函数或路由的redirectTo函数以及在路由的resolve对象中指定的函数将不再导致对$exceptionHandler()
的调用。除此之外,一切都将继续以相同的方式运行;即,承诺将被拒绝,路线转换将被取消,$routeChangeError
事件将被广播等。
-- AngularJS Developer Guide - Migrating from V1.5 to V1.6 - $q
发布于 2014-04-27 23:24:16
Angular的$q
使用一种约定,即无论是否被捕获,抛出的错误都会被记录下来。相反,如果你想发出拒绝的信号,你需要这样return $q.reject(...
:
function f2() {
var deferred = $q.defer();
// An exception thrown here is handled properly
return $q.reject(new Error("err"));//throw "err";
deferred.resolve("done f2");
return deferred.promise;
}
这是为了区分拒绝和像SyntaxError这样的错误。就我个人而言,这是一个我不同意的设计选择,但这是可以理解的,因为$q
很小,所以你不能真正构建一个可靠的未处理的拒绝检测机制。在像Bluebird这样更强大的库中,这类事情不是必需的。
顺便说一句--永远,永远不要抛出字符串:那样你就会错过堆栈跟踪。
发布于 2014-04-28 00:00:25
它是一个bug吗?
不是的。查看source for $q会发现,创建了一个特意创建的try / catch块来响应在回调中引发的异常
deferred.reject
...也被浏览器的错误处理捕获。
为了澄清,这个异常不是由浏览器直接处理的,而是作为一个错误出现的,因为Angular调用了console.error
如何才能真正用$q捕获异常?
回调将在一段时间后执行,此时当前调用堆栈已清除,因此您将无法将外部函数包装在try
/ catch
块中。但是,您有两个选项:
try
/catch
块中:您可以将其更改为完全不执行任何操作,这样控制台的错误日志中就不会有任何内容,但我不建议这样做。
https://stackoverflow.com/questions/23324942
复制相似问题