Bridging to Promises
Promises are a defacto standard within JavaScript community and is part of the ECMAScript Standard. A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then
method, which registers callbacks to receive either a promise’s eventual value or the reason why the promise cannot be fulfilled. You can create them very easily where the constructor has two functions, resolve
and reject
which resolves the value or rejects it for a given reason. RxJS is fully committed to standards and has native support for Promises for any number of methods where they can be used interchangeably with Observable sequences.
The advantage that you get when you intermix Promises with Observable sequences is that unlike the ES6 Promise standard, you get cancellation semantics which means you can disregard values if you no longer are interested. One of the biggest problems around Promises right now are around cancellation, as to cancel the operation, such as an XHR is not easily done with the existing standard, nor is it to only get the last value to ensure no out of order requests. With Observable sequences, you get that behavior for free in a multicast behavior, instead of the unicast Promise behavior.
The following list of operators natively support Promises:
Rx.Observable.amb
|Rx.Observable.prototype.amb
Rx.Observable.case
Rx.Observable.catch
|Rx.Observable.prototype.catch
Rx.Observable.combineLatest
|Rx.Observable.prototype.combineLatest
Rx.Observable.concat
|Rx.Observable.prototype.concat
Rx.Observable.prototype.concatMap
Rx.Observable.prototype.concatMapObserver
Rx.Observable.defer
Rx.Observable.prototype.flatMap
Rx.Observable.prototype.flatMapLatest
Rx.Observable.forkJoin
|Rx.Observable.prototype.forkJoin
Rx.Observable.if
Rx.Observable.merge
Rx.Observable.prototype.mergeAll
Rx.Observable.onErrorResumeNext
|Rx.Observable.prototype.onErrorResumeNext
Rx.Observable.prototype.selectMany
Rx.Observable.prototype.selectSwitch
Rx.Observable.prototype.sequenceEqual
Rx.Observable.prototype.skipUntil
Rx.Observable.startAsync
Rx.Observable.prototype.switch
Rx.Observable.prototype.takeUntil
Rx.Observable.prototype.debounceWithSelector
Rx.Observable.prototype.timeoutWithSelector
Rx.Observable.while
Rx.Observable.prototype.window
Rx.Observable.withLatestFrom
Rx.Observable.zip
|Rx.Observable.prototype.zip
Because of this, we can now do a number of very interesting things such as combining Promises and Observable sequences.
var source = Rx.Observable.range(0, 3)
.flatMap(x => Promise.resolve(x * x));
var subscription = source.subscribe(
x => console.log('onNext: %s', x),
e => console.log('onError: %s', e),
() => console.log('onCompleted'));
// => onNext: 0
// => onNext: 1
// => onNext: 4
// => onCompleted
This is just scratching the surface of what Promises and RxJS can do together so that we have first class single values and first class multiple values working together.
Converting Promises to Observable Sequences
It's quite simple to convert a Promise object which conforms to the ES6 Standard Promise where the behavior is uniform across implementations. To support this, we provide the Rx.Observable.fromPromise
method which calls the then
method of the promise to handle both success and error cases.
In the following example, we create promise objects using RSVP library.
// Create a promise which resolves 42
var promise1 = new RSVP.Promise((resolve, reject) => resolve(42));
var source1 = Rx.Observable.fromPromise(promise1);
var subscription1 = source1.subscribe(
x => console.log('onNext: %s', x),
e => console.log('onError: %s', e),
() => console.log('onCompleted'));
// => onNext: 42
// => onCompleted
// Create a promise which rejects with an error
var promise2 = new RSVP.Promise((resolve, reject) => reject(new Error('reason')));
var source2 = Rx.Observable.fromPromise(promise2);
var subscription2 = source2.subscribe(
x => console.log('onNext: %s', x),
e => console.log('onError: %s', e),
() => console.log('onCompleted'));
// => onError: reason
Notice that in this sample, these promises become observable sequences which we can manipulate further. The Querying Observable Sequences topic will show you how you can project this sequence into another, filter its content, so that your application will only receive values that satisfy a certain criteria.
Converting Observable Sequences to Promises
Just as you can convert a Promise to an Observable sequence, you can also convert an Observable sequence to a Promise. This either requires native support for Promises, or a Promise library you can add yourself, such as Q, RSVP, when.js among others. These libraries must conform to the ES6 standard for construction where it provides two functions to resolve or reject the promise.
var p = new Promise((resolve, reject) => resolve(42));
We can use the toPromise
method which allows you to convert an Observable sequence to a Promise. This method accepts a Promise constructor, and if not provided, will default to a default implementation. In this first example, we will use RSVP to construct our Promise objects.
// Return a single value
var source1 = Rx.Observable.just(1).toPromise(RSVP.Promise);
source1.then(
value => console.log('Resolved value: %s', value),
reason => console.log('Rejected reason: %s', reason));
// => Resolved value: 1
// Reject the Promise
var source2 = Rx.Observable.throwError(new Error('reason')).toPromise(RSVP.Promise);
source2.then(
value => console.log('Resolved value: %s', value),
reason => console.log('Rejected reason: %s', reason));
// => Rejected reason: Error: reason
If an implementation is not given with the toPromise
method, it will fall back to the Promise implementation specified in the Rx.config.Promise
field. By default this will be set to the runtime's ES6 Promise implementation, but can easily be overridden by specifying the configuration information.
Rx.config.Promise = RSVP.Promise;
var source1 = Rx.Observable.just(1).toPromise();
source1.then(
value => console.log('Resolved value: %s', value),
reason => console.log('Rejected reason: %s', reason));
// => Resolved value: 1
If you are in a pure ES6 environment, this should just work without any settings on your part as it will use the runtime's ES6 Promise implementation.
var source1 = Rx.Observable.just(1).toPromise();
source1.then(
value => console.log('Resolved value: %s', value),
reason => console.log('Rejected reason: %s', reason));
// => Resolved value: 1
Concepts