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,
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:
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.
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.
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