自定义ExceptionHandler更改检测滞后 [英] Custom ExceptionHandler change detection lag

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

问题描述

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

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.

我看到的问题是,自定义ExceptionHandler提交给AlertsService的错误在遇到另一个错误之前不会反映在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!

下面的示例代码,请此处:

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

原始

更改检测不会在click事件的末尾运行.

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));
}

,然后在call中调用更改检测,例如

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);
}

> 柱塞示例

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

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