Javascript 如何覆盖$exceptionHandler实现

Javascript 如何覆盖$exceptionHandler实现,javascript,exception-handling,angularjs,Javascript,Exception Handling,Angularjs,每当抛出javascript异常时,我们都需要做一些额外的事情 从$exceptionHandler上的文档: 角度表达式中任何未捕获的异常都被委托给此服务。默认实现只是将其委托给$log.error,并将其记录到浏览器控制台中 它说的是“默认实现”,这让我觉得有一种方法可以为服务提供我们自己的实现,并在抛出异常时执行我们想要的操作。我的问题是,你是怎么做到的?我们如何使所有异常保持在此服务上,然后提供我们想要的功能?您可以通过创建具有相同名称的服务来覆盖$exceptionHandler功能:

每当抛出javascript异常时,我们都需要做一些额外的事情

$exceptionHandler
上的文档:

角度表达式中任何未捕获的异常都被委托给此服务。默认实现只是将其委托给$log.error,并将其记录到浏览器控制台中


它说的是“默认实现”,这让我觉得有一种方法可以为服务提供我们自己的实现,并在抛出异常时执行我们想要的操作。我的问题是,你是怎么做到的?我们如何使所有异常保持在此服务上,然后提供我们想要的功能?

您可以通过创建具有相同名称的服务来覆盖
$exceptionHandler
功能:

var mod = angular.module('testApp', []);

mod.factory('$exceptionHandler', function () {
    return function (exception, cause) {
        alert(exception.message);
    };
});
请参阅以获取示例。如果注释掉
$exceptionHandler
的工厂定义,您将看到错误将记录到控制台,而不是向控制台发出警报

下面是一个示例,它使用
$injector
注入其他服务,如
$http


注意:如果您不想覆盖
$exceptionHandler
(或其他内置服务)的现有功能,请参阅以获取有关如何装饰服务的信息。

我发现的另一个选项是通过该函数“装饰”
$exceptionHandler
。如果您想将原始实现用作自定义实现的一部分,这将为您提供对原始实现的引用。所以,你可以这样做:

mod.config(function($provide) {
    $provide.decorator("$exceptionHandler", ['$delegate', function($delegate) {
        return function(exception, cause) {
            $delegate(exception, cause);
            alert(exception.message);
        };
    }]);
});
它将执行原始异常处理程序所执行的操作,以及自定义功能


查看此图。

您可以覆盖任何服务/工厂,甚至$cookieStore。如果您想要一个全面的、可配置的对象,请访问以下内容:


所以,基本上你可以覆盖任何服务,最后一个定义获胜,对吗?我更喜欢@dnc253的解决方案而不是这个。通过使用“decorator”功能,您可以保留现有的行为,并允许其他decorator参与操作。如果你在其他地方出于不同的原因已经这样做了,那么这一个将破坏已经存在的任何东西,包括你自己的代码。我完全同意装饰者是一种更干净的方法。尽管装饰者看起来更好,如果您想使用工厂或在模块运行时未初始化的任何东西,这似乎是一个很好的解决方案。如果您在一个单独的、包含的模块中配置它,Config会起作用吗,如果这是最后一个定义?+1-这肯定是处理问题的更好方法。使用了这个,但它似乎不能正确地进行缩小!它是否像在编辑中那样使用数组表示法?您必须在此处执行此操作,就像在其他任何地方使用依赖项注入进行缩小一样。@dnc253是的,是的,我在找到它后才应用了编辑。我建议您注意:这可能会吞没您的karma单元测试中的所有异常,这肯定是不希望发生的。请选择“$provide.decorator”解决方案作为此问题的答案。
var myApp = angular.module('myApp', []);

//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!"
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});


function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {

   helloWorld.sayHello(),
}