HELP :: Navigation triggered outside Angular zone

One of the trickiest parts about writing apps for MacOS back in the pre-Darwin days was trap patching. It was sort of like the prototype shenanigans people do in JavaScript to modify the behavior of built-in objects, but even more powerful and dangerous. Apple basically used illegal instructions (from the CPU’s POV) to implement the OS. The illegal instruction would suspend whatever the CPU was ordinarily doing and jump to a fixed place, where the OS would do its thing, and then return control to normal.

When you patched these OS routines, you had to be super-careful about what other parts of the OS you called, because much of it wasn’t reentrant and you could crash the entire computer, frequently in intermittent and hard-to-reproduce fashion. The safest thing to do in a trap patch was simply to set a flag and wait for a more predictable time to respond to it.

Maybe a page from that book would help you here. Instead of doing anything heavy in a “global error handler” (which sounds like something that can get called from all sorts of sketchy situations), just throw up a flare in there and react to it in a safer environment:

class ErrorService {
  private errors$ = new Subject<string>();
  watchErrors(): Observable<string> { return this.errors$; }
  globalErrorHandler() {
    this.errors$.next("ruh roh");
  }
}
// could be anywhere, really, but I know there's an AppComponent
class AppComponent {
  constructor(router: Router, errorer: ErrorService) {
    errorer.watchErrors().subscribe(err => router.navigate(["/error"]);
  }
}

Promise.resolve can be used to similar effect: both RxJS and Promise are zone-aware, so by the time the Observable’s emission is seen by the subscribe block (or a then block in the Promise case), you are going to be back in the Angular zone, even if the globalErrorHandler happened to be called from outside it.

One thing I would definitely not do (although you’ll likely see others who disagree) is to inject NgZone and call its run method. I feel zones are an internal implementation detail of Angular, and shouldn’t be in app code.

1 Like