1. 程式人生 > >用VSCode開發一個asp.net core 2.0+angular 5項目(4): Angular5全局錯誤處理

用VSCode開發一個asp.net core 2.0+angular 5項目(4): Angular5全局錯誤處理

create 打印 事件 如果 log 異步操作 truct gin 按鈕

第一部分: 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://[email protected]/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.

用VSCode開發一個asp.net core 2.0+angular 5項目(4): Angular5全局錯誤處理