In Angular 1, I would frequently use the “resolve” property of routes in order to pre-load data for the route’s controller. This was accomplished with a Promise that would prevent the route from loading until the Promise was resolved. In Angular 2 this concept still exists, although now you can leverage Observables as well.
In my research I found plenty of examples on how to use Observables in your route’s resolve property, but almost no examples of Promises. Since I was more familiar and comfortable with Promises at the time, I wanted to use a Promise to fetch the necessary data for my route. I had to more or less piece together how to use a Promise to resolve a route, and then once that was done I was of course curious how it would differ had I opted to use an Observable instead.
I pieced together this Plunkr to compare side-by-side using Promises and Observables for a route’s resolve. This example lets you switch between two different routes that resolve some mock data using either a Promise or an Observable, while outputting some logging information to the console (so make sure you have your console window open).
I hope the code is simple enough that anyone with basic knowledge of Angular 2 and Routing could follow along, but I’ll touch on the more interesting aspects of the example.
First, the resolver classes:
@Injectable() export class ObservableResolver implements Resolve<string> { constructor() { } resolve(route:ActivatedRouteSnapshot, state:RouterStateSnapshot): Observable<string> { console.log("Resolving Observable..."); let mockData:string = ""; return new Observable(observer => { setTimeout(() => { console.log("Resolved Observable"); mockData = "Mock Data String (O)"; observer.next(mockData); console.log("Emitted new Observable data"); setTimeout(() => { console.log("Completing Observable"); observer.complete(); }, 1000); }, 2000); }); } } @Injectable() export class PromiseResolver implements Resolve<string> { constructor() { } resolve(route:ActivatedRouteSnapshot, state:RouterStateSnapshot): Promise<string> { console.log("Resolving Promise..."); let mockData:string = ""; return new Promise<string>(resolve => setTimeout(resolve, 2000)).then(() => { console.log("Resolved Promise"); mockData = "Mock Data String (P)"; return mockData; }); } }
The PromiseResolver is pretty standard for anyone who’s familiar with Promises. What’s interesting to note is that despite the fact that the class returns a Promise, you still access this data through an Observable. I’m not 100% sure about this, but is seems that when you define a resolve object, the property names used for each resolve get “injected” into the data object of the ActivatedRoute as an Observable. This is why the ResolveWithPromise and ResolveWithObservable components access the mock data the same way, even though the resolve types are different.
Tangent aside, the PromiseResolver isn’t that interesting for anyone who’s been using Promises for any amount of time. It’s the ObservableResolver that’s using the new and shiny functionality. The resolve() function of the class returns a new Observable object that waits for 2 seconds before updating the mock data. However if that was all the Observable did, the route would never resolve! Since an Observable can actually trigger its “data update” callback as many times as it wants (as opposed to a Promise which can only trigger its resolve callback once), the route is actually waiting for the “Complete” event from the Observable before allowing the route to load.
In my opinion, based on what I’ve learned so far, Promises seem to be “cleaner” for route resolution since the route isn’t actually going to subscribe and keep “listening” to any Observables. In a basic sense, Promises are a one-and-done Observable, or to put it another way Observables can be thought of as a Promise that can repeatedly fire its resolve callback. Route resolves don’t care about data updates – they want the necessary data and then to continue loading the route. Promises seem to fit that design better but it’s nice to know that Observables work as well (since in many of our Angular 2 applications we’re using Observables for data fetch calls).
It’s not anything really new or groundbreaking, but I didn’t really understand how Observables interacted with a route’s resolve property prior to this. Plus, having come from a world a Promises I really wanted a good way to compare the two methods in the same context. Hopefully this example helps clear things up for others as well.