Skip to content

Instantly share code, notes, and snippets.

@endash
Last active July 14, 2016 02:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save endash/1f961830d0c5b744598a to your computer and use it in GitHub Desktop.
Save endash/1f961830d0c5b744598a to your computer and use it in GitHub Desktop.
Asynchronous observables in Angular 2 and their issues

The problem

In some situations it is beneficial to force an observable to resolve subscriptions asynchronously, via use of the observeOn operator. Failing that, it is at least possible to force an observable to resolve asynchronously. The issue from an Angular perspective is that we usually want our subscribe callback to run in the Angular zone, otherwise change detection won't automatically kick off. Additionally, inside an asynchronous observer callback setTimeout does not run in the app zone, eliminating a potentially obvious solution. To code defensively, one might use NgZone.run wherever there's a possibility that an observable is async. Unfortunately, this has the knock-on effect of causing errors if the observable is not async. To prevent those errors observables can be uniformly forced async, with NgZone used in the subscribe callback, resulting in uniform, proper behaviour. These measures have a not insubstantial technical cost.

I am not presently aware of a way to ensure that callbacks on async observables are wrapped in NgZone except for manual use inside the callbacks themselves, pending further research. As such, a user's class might easily be the unwitting consumer of an async observable, and cannot reasonably expect to receive only synchronous observables. Additionally, even if there were such a mechanism, observables can be passed through and manipulated by several classes, only one of which is aware that the observable is asynchronous.

Problematically, NgZone is not readily available in all contexts, so far as I am aware. In particular, making it available to a free function is awkward, and making it available as part of a decorator (for use in a method added by that decorator, for example) is, absent a very hacky use of platform, impossible. This currently has the unfortunate consequence of forcing significant amounts of defensive boilerplate into the user's code, rather than being handled behind the scenes.

Ideal solution: ZoneScheduler

We'd have to trust that an observable was scheduled using ZoneScheduler, but that's an acceptable risk considering how much defensive code it eliminates. Depending on the use case, there could still be a runtime check for whether we're executing in the Angular zone that could throw an exception if needed.

angular/angular#4603

Plunkr: http://plnkr.co/edit/44r7L4XLCzmnW3YgxN25?p=preview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment