自定义ExceptionHandler更改检测滞后 [英] Custom ExceptionHandler change detection lag
问题描述
我正在尝试在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屋!