第一部分: http://www.cnblogs.com/cgzl/p/8478993.html
第二部分: http://www.cnblogs.com/cgzl/p/8481825.html
第三部分: https://www.cnblogs.com/cgzl/p/8525541.html
这篇文章将介绍 angular 5 的全局错误处理.
需要使用到代码: https://pan.baidu.com/s/1F0KjbwVE8_Tzfwy69Alp-A
angular 5 全局错误处理
参考文档: https://angular.io/api/core/ErrorHandler
首先按照文档在客户端项目建立 app.error-handler.ts 文件:
- import {ErrorHandler} from '@angular/core';
- export class AppErrorHandler implements ErrorHandler {
- handleError(error: any): void {
- console.log('ERROR Occurred.');
- }
- }
这里, 我们只写 log.
然后在 app.module 里面注册:
- providers: [
- TvNetworkService,
- { provide: ErrorHandler, useClass: AppErrorHandler }
- ],
然后把 tv-network-list.component.ts 里面到一个错误处理删除掉:
然后在后端到 Controller 里面抛一个异常:
然后我们试一下:
可以看到, 这个全局错误处理器正常到工作了.
先别急, 让我们在 errorhandler 里面使用 toastr 试试.
- app.error-handler.ts:
- import { ErrorHandler } from '@angular/core';
- import { ToastrService } from 'ngx-toastr';
- export class AppErrorHandler implements ErrorHandler {
- constructor(private toastr: ToastrService) { }
- handleError(error: any): void {
- // console.log('ERROR Occurred.');
- this.toastr.error('发生了错误');
- }
- }
而这时回到浏览器之后, 发生了错误:
之所以发生这个错误, 是因为 AppErrorHandler 在 angular 引入 Toastr 模块之前就初始化了.
我们可以这样处理:
- import { ErrorHandler, Injectable, Injector, Inject } from '@angular/core';
- import { ToastrService, Toast } from 'ngx-toastr';
- @Injectable()
- export class AppErrorHandler implements ErrorHandler {
- constructor(private injector: Injector) { }
- private get toastr(): ToastrService {
- return this.injector.get(ToastrService);
- }
- handleError(error: any): void {
- this.toastr.error('发生了错误');
- }
- }
使用 Injector 来手动注入 ToastrService.
回到浏览器:
并没有弹出错误信息!!!!, 但是来回切换菜单后, 开始显示错误信息了, 貌似有点迟钝.
这是什么原因呢? 首先, 我们得了解以下这个东西:
Zone
首先到首先, 需要了解以下 execution context, 程序执行到上下文, 但是这些东西到定义看了之后可能会让人迷糊. 所以还是先看这段代码吧:
- const Zone = {
- run: (callback) => {
- if (this.beforeTask) {
- this.beforeTask();
- }
- callback();
- if (this.afterTask) {
- this.afterTask();
- }
- }
- };
- Zone.beforeTask = () => {
- console.log('Before Task.');
- };
- Zone.afterTask = () => {
- console.log('After Task.');
- };
- Zone.run(() => {
- console.log('Running...');
- });
就是定义一个 Zone, 它到 run 方法可以执行某个回调函数, 回调函数到前后还可以有一些预定义的函数, 如果它们存在就会被执行. 通过定义这些函数的内容, 我们就可以在执行 run 的回调前后添加自定义逻辑了.
回到 Angular, angular 的变化检测 (Change Detection) 功能就用到了这些东西.
比如 angular 的一个 component 有一个 click 事件, click()方法里更新了某些属性的值, 这个时候 angular 就需要进行变化检测, 如果真的发生了变化, 那么 angular 就会更新 dom, 这样我们就能看见页面的变化了. Angular 用了这个猴子补丁, 使之运行在 Zone 里面, 当点击按钮的时候, 这段代码总是在 Zone 里面执行, 在执行完 click 处理方法之后, angular 会执行变化检测动作.
angular 应该是这样来进行猴子补丁的:
- const Zone = {
- run: (callback) => {
- if (this.beforeTask) {
- this.beforeTask();
- }
- callback();
- if (this.afterTask) {
- this.afterTask();
- }
- }
- };
- Zone.beforeTask = () => {
- console.log('Before Task.');
- };
- Zone.afterTask = () => {
- console.log('After Task.');
- };
- Zone.run(() => {
- console.log('Running...');
- });
- var _setTimeout = setTimeout;
- setTimeout = (callback, timeout) => {
- Zone.run(() => {
- _setTimeout(callback, timeout);
- });
- };
- click(() => {
- console.log('设置 Timeout');
- });
由于这个是异步的, 所以打印到控制台到顺序可能是: Before Task, After Task, 设置 Timeout.
js 运行时里, 有一个信息队列. 任何时候出现一个异步操作, 队列里就会推进去一条信息, js 运行时会训话这个队列, 一个个把消息推出队列, 然后调用这个消息到回调函数. 对于这个例子来说就是 setTimeout().
所以就出现了 Zone.js 这个库.
Zone.js 就是一个执行的上下文, 它可以在不同的异步操作之间进行持久性传递.
Angular 就使用了这个库, 在它之上建立了 ngZone 这个模块. 就这样 angular 在发生异步操作后进行到了变化检测.
浏览器里面主要有这几种异步操作: dom 事件, ajax 请求, 定时回调之类的.
回到项目里的 app.error-handler.ts:
这句话呢就跑出了 angular zone 的范围...
所以当错误发生的时候, toastr 的 error 方法被调用了(状态改变了), 但是 angular 并不知道这个变化, 所以 toastr 通知没有显示.
那如何解决呢?
使用 ngZone:
- import { ErrorHandler, Injectable, Injector, Inject, NgZone } from '@angular/core';
- import { ToastrService, Toast } from 'ngx-toastr';
- @Injectable()
- export class AppErrorHandler implements ErrorHandler {
- constructor(
- private injector: Injector,
- private ngZone: NgZone
- ) { }
- private get toastr(): ToastrService {
- return this.injector.get(ToastrService);
- }
- handleError(error: any): void {
- this.ngZone.run(() => {
- this.toastr.error('发生了错误');
- });
- }
- }
下面试试页面:
这次没有任何问题了.
Logging Errors 记录错误
您可以自己写一个后台 api 来记录日志, 但是这里我介绍一个专门做 logging 的云服务, sentry.io. https://sentry.io/
首先请您自己注册账户.
然后创建一个项目, 选择 angular:
然后点击下面按钮 Create Project.
然后它给出了安装和配置的说明:
首先执行命令安装.
然后, 配置:
- import * as Raven from 'raven-js';
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule, ErrorHandler } from '@angular/core';
- import { AppComponent } from './app.component';
- Raven
- .config('https://fa66d9390ab04c7f8e8c82ad0613fb4e@sentry.io/301095')
- .install();
- @NgModule({
- imports: [ BrowserModule ],
- declarations: [ AppComponent ],
- bootstrap: [ AppComponent ],
- providers: [ { provide: ErrorHandler, useClass: AppErrorHandler } ]
- })
- export class AppModule { }
按照说明进行配置, 我们做一些调整, 这里红色部分是每个用户都不一样都.
最后修改 app.error-handler.ts:
- import { ErrorHandler, Injectable, Injector, Inject, NgZone } from '@angular/core';
- import { ToastrService, Toast } from 'ngx-toastr';
- import * as Raven from 'raven-js';
- @Injectable()
- export class AppErrorHandler implements ErrorHandler {
- constructor(
- private injector: Injector,
- private ngZone: NgZone
- ) { }
- private get toastr(): ToastrService {
- return this.injector.get(ToastrService);
- }
- handleError(error: any): void {
- Raven.captureException(error);
- this.ngZone.run(() => {
- this.toastr.error('发生了错误');
- });
- }
- }
回到浏览器的错误页面, 触发错误后, 大约几分钟后, 来到 sentry.io 网站查看:
今天先写到这, 明天后天写以下 angular5 上传文件到 asp.net core web api.
来源: https://www.cnblogs.com/cgzl/p/8536350.html