Angular 2:自定义ExceptionHandler更改检测滞后 [英] Angular 2: Custom ExceptionHandler Change Detection Lag
问题描述
我正在尝试在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);
}
这篇关于Angular 2:自定义ExceptionHandler更改检测滞后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!