Promises vs Observables for AngularJS-to-Angular migration
Tags: javascript, rxjs, webdev, angular
Published: 2019-05-15 08:33:12

---
title: Promises vs Observables for AngularJS-to-Angular migration
published: true
description: _AngularJS(Angular 1) was using Promises heavily for HTTP calls, while Angular has network calls wrapped in Observables. This caused that some devs met specific issues while migrating projects from AngularJS to Angular. I want to address these issues here and describe why they can appear at all by reviewing typical differences between Observables and Promises_.
tags: javascript, rxjs, webdev, angular, angularjs
canonical_url: https://itnext.io/promises-vs-observables-for-angularjs-to-angular-migration-1161afacef7e
---

_AngularJS(Angular 1) was using Promises heavily for HTTP calls, while Angular has network calls wrapped in Observables. This caused that some devs met specific issues while migrating projects from AngularJS to Angular. I want to address these issues here and describe why they can appear at all by reviewing typical differences between Observables and Promises_.

 ![](https://cdn-images-1.medium.com/max/1600/1*u1_Ed0HBa5iO7TFe_tkM8w.jpeg)
*Observables — more capabilities for web-devs. (pic by [mediamodifier](https://pixabay.com/ru/users/mediamodifier-1567646/))*


> Pre-requisites: you should know JS Promises


**Observables and Promises — short intro**

At first glance — Observables are just advanced Promises: Promises emits one value and complete (resolve), Observables emit 0, one or many values and complete as well (emit and complete are different actions). For HTTP service in AngularJS and Angular provides only one value — so seems both frameworks work very similar in this case.


```javascript
// Observables in Angular 2+
const sourse$ = this.httpServie.get('https://some_url.com')
source$.subscribe(
	(data) => handelData(data), // success handler
  	(err) => handleError(err),  // error handler
    () => completeHandler() // onComplete handler
)

// Promises in AngularJS
const soursePromise = http$.get('https://some_url.com')
soursePromise.then(
	(data) => handelResolve(data), // resolve handler
  	(err) => handleReject(err) // reject handler
)
```

And one may think that it is enough just rename **_$http_** to **_this.httpService_** , **_then_** to **_subscribe_** and everyone will be happy. In very simple apps it even can work — but if you application is doing something more then ‘Hello world’ — plz pay attention to these differences.

#### #1 Eager vs&nbsp;Lazy

Take a look at example below:

```javascript
//Promise-wrapped http request
saveChanges(data) {
  return $http.post('https://some_url.com', data)
}


//Observable-wrapped http request
saveChanges(data) {
  return this.httpService.post('https://some_url.com', data) // doesn't do request!
}
```

When I call **saveChanges** method — the first example with Promise-wrapped request will work as expected. But in seconds Observable-wrapped example nothing will happen because Observables are **lazy-evaluated** while Promises are **eager-evaluated.**

This means that Promises doesn’t care whether they have some subscribers to get their result or not. But Observables (to be precise — cold Observable) will be cold only if we subscribe to them. In the case above you should subscribe to Observable returned by **saveChanges** function.

```javascript
saveChanges(data).subscribe()
```

To keep an eye on it — use _rxjs-no-ignored-observable_ rule from [rxjs-tslint-rules](https://github.com/cartant/rxjs-tslint-rules/blob/master/source/rules/rxjsNoIgnoredObservableRule.ts) by [Nicholas Jamieson](https://medium.com/@cartant).

#### **#2 Promises cannot be canceled while Observables can be unsubscribed**

Again, start with example when on input text change we do search on a back-end:

```javascript
// html
<input ngKeyup="onKeyUp($event)">
  
//Promise-wrapped HTTP request
saveChanges(event) {
  const text = event.target.value;
  $http.get('https://some_url.com?search=' + text)
    .then((searchResult) => showSearchResult(searchResult))
}
```

What is a drawback here — that you cannot reject results of the previous request if the user continues typing (debounce make this problem a bit less but doesn’t eliminate it). And one more issue — race condition is possible (when later request result will come back faster then earlier one — so we get incorrect response displayed).

Observable can avoid this concern quite elegant with [**switchMap**](https://rxjs-dev.firebaseapp.com/api/operators/switchMap) operator:


```javascript
// html template
<input id="search">
  
//Observable-wrapped HTTP request
inputElem = document.querySelector('#search');
search$ = fromEvent(inputElem, 'keyup');

ngOnInit() {
  
  search$.pipe( // each time new text value is emitted
  	switchMap((event) => { // switchMap cancel previous request and send a new one
      const text = event.target.value;
      return this.httpService.get('https://some_url.com?search=' + text);
    })
  )
    .subscribe((newData) => this.applyNewData(newData))  // use new data
}
```

Here we convert input text typing to observable values emissions. Each time new text value is emitted switchMap operator will cancel previous network request (if it is not finished yet) and send a new one.

* * *

_Packtpub.com and I prepared a whole_ [**_RxJS course_**](https://www.udemy.com/hands-on-rxjs-for-web-development/) _with many other details of how you can solve your every-day developer’s tasks with this amazing library. It can be interesting for beginners but also contains advanced topics._ [**_Take a look!_**](https://www.udemy.com/hands-on-rxjs-for-web-development/)

* * *

#### #3 No built-in retry or repeat logic for Promises. ‘[**repeat**](https://rxjs-dev.firebaseapp.com/api/operators/repeat) **’** and ‘[**retry**](https://rxjs-dev.firebaseapp.com/api/operators/retry) **’** operators for Observables.

You can implement retry logic with Promises but it looks a bit cumbersome:

```javascript
var request = function() {
  $http({method: 'GET', url: path})
    .success(function(response) {
      results.resolve(response)
    })
    .error(function() {
      if (counter < MAX_REQUESTS) {
        request();
        counter++;
      } else {
        results.reject("Could not load after multiple tries");
      }
    });
};

request();
```

While same code Observables will be much shorter:

```javascript
this.httpService.get('https://some_url.com/data').pipe(
	retry(MAX_REQUESTS)
)
```

Read more about repeat and retry operators use-cases in [my article](https://dev.to/oleksandr/rxjs-operators-retry-vs-repeat-5gn).

#### #4 A small number of Promises combination tools. Observables provide a wide variety of operators for&nbsp;that.

For Promises all the possibilities you can combine resulsts are:

**Promise.all**  — waiting for all Promises to be resolved and then provide array of results.

**Promise.race**  — wait till one of the Promises is resolved and return that result.

* * *

Observables provide very rich ammo for making combinations:

* **combineLatest(observable1, observable2,…)** — waits for any of observable to emit and provide array of last emitted values from all observables (result: [value\_obs1, value\_obs2,..]). Very good if you should update page on a new data from a few different sources.

* **observable1.pipe(_withLatestFrom_(observable2) **— on each value from observable1 also provide last emitted value for observable2 (result: [value\_obs1, value\_obs2]).

* **forkJoin(observable1, observable2,…)**— analog for Promise.all — waits till all Observables are complete and then emits an array of last values from all of the argument observables.

* **zip** **(observable1, observable2,…)**— waits for all of the argument observables to emit values with the same index and provide an array of emitted values with the same index (result: [value\_obs1, value\_obs2,..]).

* **race(observable1, observable2,…) — **returns an Observable that mirrors the first source Observable to emit an item.

* **merge(observable1, observable2,…) — **subscribes to every argument observable and re-emits values from all of them.

* **switchAll**  — if previous Observable is not completed — cancel it and subscribe to new one.

* **concat(**observable1, observable2,…**)** — start next Observable sequence only after previous one is done (emits values one by one after each specific Observable completion)

And many more ([switchMap](https://rxjs-dev.firebaseapp.com/api/operators/switchMap), mergeMap, [partition](https://rxjs-dev.firebaseapp.com/api/index/function/partition), [iif](https://rxjs-dev.firebaseapp.com/api/index/function/iif), [groupBy](https://rxjs-dev.firebaseapp.com/api/operators/groupBy), [window](https://rxjs-dev.firebaseapp.com/api/operators/window), etc)

You can learn more about these operators here:

1. [Learn to combine RxJs sequences with super intuitive interactive diagrams](https://blog.angularindepth.com/learn-to-combine-rxjs-sequences-with-super-intuitive-interactive-diagrams-20fce8e6511)
2. [Official docs with examples](https://rxjs-dev.firebaseapp.com/api)
3. “Hands-on RxJS for Web Development” [video-course](https://www.packtpub.com/web-development/hands-rxjs-web-development-video).

#### #5 Easy to prevent race condition with Observables and hard - with Promises.

Say we periodically make a network request for updated data. But in some situations later request result will come back faster than earlier one — so we get incorrect (earlier) response displayed as last.

```javascript
getData() {
  $http.get('https://some_url.com/data')
    .then((searchResult) => {
  		doSomething(searchResult)
    }
  })
}

setTimeout(getData, 5000);
```

This code can be possibly affected by the race condition issue.

To prevent this with Observable-wrapped requests we can use [concatMap](https://rxjs-dev.firebaseapp.com/api/operators/concatMap) operator.

```javascript
interval(5000).pipe(
	concatMap(() => this.httpService.get('https://some_url.com/data'))
)
.subscribe(doSomethingWithData)
```

**concatMap** will make next network call only after previous is done and handled. Of course, if you don’t need previous results — then use switchMap (as in the first example of this article).

#### Conclusion

During migration from AngularJS (uses promises for network calls) to Angular (uses Observable) you should be aware of possible differences of Promises and Observable. Hope my article helped you to clarify this topic. Now it’s time to migrate!

Like this article? Let’s keep in touch on [Twitter](https://twitter.com/El_Extremal).

This post was originally published in [ITNEXT](https://itnext.io/promises-vs-observables-for-angularjs-to-angular-migration-1161afacef7e).

* * *

_Starting from section 4 of my_ [**_RxJS video course_**](https://www.udemy.com/hands-on-rxjs-for-web-development/) _advances staff is reviewed — so if you familiar with RxJS already — you can find something useful for you as well: higher-order observables, anti-patterns, schedulers, unit testing, etc!_ [**_Give it a try_**](https://www.udemy.com/hands-on-rxjs-for-web-development/) **_!_**