Angular 2:自定义ExceptionHandler更改检测滞后 [英] Angular 2: Custom ExceptionHandler Change Detection Lag

查看:68
本文介绍了Angular 2:自定义ExceptionHandler更改检测滞后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Angular 2应用程序中实现自定义 ExceptionHandler ,该应用程序将未捕获的错误提交给自定义 AlertsService 。目标是允许主 App 组件订阅 AlertsService 提供的警报,以便它可以显示用户界面中的错误。

I'm trying to implement a custom ExceptionHandler in an Angular 2 app which submits uncaught errors to a custom AlertsService. The goal is to allow the main App component to subscribe to the alerts provided by the AlertsService so that it can display the errors in the UI.

我看到的问题是自定义提交给 AlertsService 的错误在遇到另一个错误之前,code> ExceptionHandler 不会反映在UI中。这导致UI始终是 AlertsService 实际提供的一个警告。

The problem I'm seeing is that errors submitted to the AlertsService by the custom ExceptionHandler are not reflected in the UI until another error is encountered. This causes the UI to always be one alert behind what is actually being provided by the AlertsService.

我的猜测是这种行为与更改检测和ExceptionHandler的特殊情况有关,但我不确定从何处开始。期待Angular2专家的帮助!

My guess is that this behavior has something to do with change detection and the special case of the ExceptionHandler, but I'm not sure where to go from here. Looking to the Angular2 experts for help!

下面的示例代码,插入此处: https://plnkr.co/edit/xPoWCELA9IHqeLBS4wXs?p=preview

Sample code below, plunk here: https://plnkr.co/edit/xPoWCELA9IHqeLBS4wXs?p=preview

import { Component, ExceptionHandler, Injectable, OnInit, provide } from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Subject } from 'rxjs/Subject'

export interface Alert {
  message: string;
}

@Injectable()
export class AlertsService {

  private alertTriggeredSubject = new Subject<Alert>();

  alertTriggered = this.alertTriggeredSubject.asObservable();

  triggerAlert(message: string) {
    this.alertTriggeredSubject.next(<Alert>{ message: message });
  }

}

@Injectable()
export class CustomExceptionHander {

  constructor(private alertsService: AlertsService) { }

  call(exception, stackTrace = null, reason = null) {
    this.alertsService.triggerAlert(exception.originalException);
    console.error('EXCEPTION:', exception);
  }
}

@Component({
  selector: 'child-component',
  template : `
  <h3>Child</h3>
  <div id="child">
    <button (click)="breakMe()">Break Me!</button>
    <div>Alerts Sent:</div>
    <ul><li *ngFor="let error of errors">{{error}}</li></ul>
  </div>`
})
export class ChildComponent {

  errors: string[] = [];
  numErrors = 0

  breakMe() {
    this.numErrors++;
    let error = `I broke it (${this.numErrors})`;

    // The error added to the array below is never reflected in the 
    // "Alerts Sent:" <ul>...not sure why
    this.errors.push(error);
    console.info('ChildComponent.errors', this.errors);

    // Simulate unhandled exception
    throw new Error(error);
  }
}

@Component({
  selector: 'my-app',
  template : `
  <h3>Parent</h3>
  <div id="parent">
    <div>Alerts Received:</div>
    <ul><li *ngFor="let alert of alerts">{{alert.message}}</li></ul>
    <child-component></child-component>
  </div>`
  directives: [ChildComponent]
})
export class App implements OnInit {

  constructor(private alertsService: AlertsService) { }

  alerts: Alert[] = [];

  ngOnInit() {
    this.alertsService.alertTriggered.subscribe(alert => {
      this.alerts.push(alert);

      // Alert gets received, but is not reflected in the UI
      // until the next alert is received, even thought the 
      // alerts[] is up-to-date.
      console.info('App alert received:', alert);
      console.info('App.alerts:', this.alerts);
    });
  }
}

bootstrap(App, [
    AlertsService,
    provide(ExceptionHandler, { useClass: CustomExceptionHander })
]).catch(err => console.error(err));


推荐答案

更新 ExceptionHandler 已重命名为 ErrorHandler https://stackoverflow.com/a/35239028/217408

orgiginal

当处理程序抛出时,单击事件结束时不会运行更改检测。

Change detection isn't run at the end of the click event when the handler throws.

您可以手动调用更改检测但这有点复杂,因为您需要 ApplicationRef 引用和 ApplicationRef 依赖于 ExceptionHandler ,这会产生一个整洁的循环而DI无法解决循环依赖。

You can invoke change detection manually but this gets a bit complicated because you need an ApplicationRef reference and ApplicationRef depends on ExceptionHandler which makes a neat cycle and DI can't resolve cyclic dependencies.

解决方法是代替 ApplicationRef 注入 Injector 并获取 AplicationRef 势在必行

A workaround is to instead of ApplicationRef inject the Injector and acquire AplicationRef imperatively like

constructor(private alertsService: AlertsService, injector:Injector) { 
  setTimeout(() => this.appRef = injector.get(ApplicationRef));
}

然后在致电调用变更检测,如

and then in call invoke change detection like

call(exception, stackTrace = null, reason = null) {
  this.alertsService.triggerAlert(exception.originalException);
  this.appRef.tick();
  console.error('EXCEPTION:', exception);
}

Plunker示例

这篇关于Angular 2:自定义ExceptionHandler更改检测滞后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆