Skip to content
This repository has been archived by the owner on Apr 20, 2018. It is now read-only.

RxJS Version 3.0

Compare
Choose a tag to compare
@mattpodwysocki mattpodwysocki released this 04 Aug 02:12
· 684 commits to master since this release

Here is the long awaited RxJS version 3.0! This has many changes since our last release of v2.5.3. This release contains a great number of changes for the better including rx.core.js and the Rx-Core family as well as the rx.lite.js and the Rx-Lite family of libraries. Rx-Core allows you to implement the bare bones of the Observable contract so that your library is compatible with RxJS with additions for multicast operations via rx.core.binding.js and testing with rx.core.testing.js. In addition, the Rx-Lite family allows you to stick with rx.lite.js and then require only the lite packages you need as you need them.

In this release, we tried to pay down some of our technical debt that has incurred over the years since we started releasing RxJS five years ago. To that end, there are some breaking changes, hence the major version bump to 3.0 most of which are dealing with ridding ourselves of aliases that did not properly reflect the code and has reduced to a single name.

Here are some of the highlights:

  • Rx Core Packages
  • Rx Lite Packages
  • New Operators
  • Rx.Observable.fromEvent Changes
  • Rx.Observable.spawn Changes
  • Rx.Observable.prototype.scan Changes
  • OrDefault Method Changes
  • Deprecations
  • Performance Improvements
  • Bug Fixes

What's next for us? We're working on the following items during the 3.x timeframe including:

  • Bonsai Tree serialization to allow RxJS to cross boundaries
  • Single module exports per operator
  • Moving towards a new testing system

Rx Core Packages

There have been many questions over the years as to a minimal implementation of RxJS so that developers can provide shims for Observables instead of shipping the entire library. To that end, we have shipped a minimal implementation of Rx Observables along with a base scheduler and some disposables. We also ship for those who want multicast behavior on their created Observables we also ship that library as well. And finally, we also have a shim for testing just in case you want to test your shims in the exact same style that RxJS uses.

We ship three main files to support this:

  • rx.core.js
  • rx.core.binding.js
  • rx.core.testing.js

Each of these can be found in their own respective NPM packages

We'd like to get them as lean and mean as possible so any suggestions and we're all ears.

Rx Lite Packages

In previous releases of RxJS, we shipped Lite packages which were meant to be a stripped down version of RxJS to the most commonly used operators. To stay more productive, developers would eventually bring in more operators as they need them with such things as time-based operators, virtual-time, testing and so forth. Not only that, but they would need to support older environments as well as newer ones. To fix this, the team has introduced a number of new NPM packages to support the Lite workflow. Each package has a compat counterpart so all the way up the chain it uses the right version of RxJS for you.

We have created the following NPM packages to support Rx Lite:

New Operators

People are always looking for new ways to combine sequences using variations of flatMap, whether it is to control the amount of concurrency to whether the first or the last value is cut and disposed. RxJS version 3.0 has added the following operators to help with those efforts.

Rx.Observable.fromEvent Changes

In previous releases, Rx.Observable.fromEvent, if given a selector function, would pass the raw arguments to the selector function to allow the developer to pick which items to project. This has been found to be clumsy so instead, the function is applied with the given arguments, thus making it a more natural experience.

For example, previously, you would have to do the following:

var Rx = require('rx');
var EventEmitter = require('events').EventEmitter;

var e = new EventEmitter();

var changes = Rx.Observable.fromEvent(e, 'changes', function (args) {
  return { first: args[0], second: args[1] };
});

This has been simplified to instead so that the arguments are directly applied on the selector function:

var Rx = require('rx');
var EventEmitter = require('events').EventEmitter;

var e = new EventEmitter();

var changes = Rx.Observable.fromEvent(e, 'changes', function (first, second) {
  return { first: first, second: second };
});

Rx.Observable.spawn Changes

Originally, RxJS shipped with a very primitive version of handling generator functions through Rx.spawn. This has been changed to Rx.Observable.spawn which now instead of returning a Node.js style callback, will now return an Observable for consistency with the rest of RxJS.

This enables a number of exciting scenarios mixing in support for Promises, Arrays, Generators, Node-style callbacks, and yes of course, Observables.

var Rx = require('rx');

var nodeCallBack = function (val) {
  return function (cb) {
    cb(null, val);
  };
};

var spawned = Rx.Observable.spawn(function* () {
  var v = yield nodeCallBack(12);
  var w = yield [24];
  var x = yield Rx.Observable.just(42);
  var y = yield Rx.Observable.just(56);
  var z = yield Promise.resolve(78);
  return v + w[0] + x + y + z;
});

spawned.subscribe(
  function (x) { console.log('next %s', x); },
  function (e) { console.log('error %s', e); },
  function () { console.log('completed'); }
);

// => next 212
// => completed

- Rx.Observable.prototype.scan Changes

In previous releases, the scan method followed the now removed aggregate method syntax which had the seed first, followed by the aggregate function. For RxJS 3.0, this has been reversed to match the reduce signature which better matches the natures of JavaScript and the Array#extras.

Previously, the signature was the following:

observable.scan(0 /*seed*/, function (acc, x) {
  return acc + x;
});

Now has been changed to the following:

observable.scan(function (acc, x) {
  return acc + x;
}, 0 /*seed*/

OrDefault Method Changes

In previous releases of RxJS, we had methods for a number of operators such as first, last, elementAt and single with OrDefault suffixes on them which determined whether they would throw on an error or return some default value. Instead of having more operators, this has been condensed into one single operator for each:

Each of those APIs have changed to allow a much nicer workflow. For example, in previous releases, we wanted to have a default value if there was no first element, then we'd have to provide the argument for the default value as the third parameter.

observable.firstOrDefault(null /*selector*/, null /*thisArg*/, 42 /*defaultValue*/);

Instead, this has been radically simplified with the following:

observable.first({defaultValue: 42});

Note that if a default value is omitted, then the function will throw upon not meeting the condition or being empty.

Deprecations

Note that the following method aliases have had their accompanied aliases removed:

MethodRemoved Aliases
catch catchError, catchException
do doAction
every all
finally finallyAction
reduce aggregate
return / just returnValue
some any
throw throwError, throwException
while whileDo

Performance Improvements

As always we continue to strive towards better performance as we continue with RxJS. To that end, we fixed a number of hot points where we could reduce closure scope and chained scopes.

The following methods were given new performance enhancements to better suit performance:

  • Rx.Observable.fromCallback
  • Rx.Observable.fromEvent
  • Rx.Observable.fromNodeCallback

Other minor changes were made to aggregation operators to reduce closure scope which had significant gains as well.

Bug Fixes

The following bug fixes were completed with many thanks to our contributors!

  • #694 - Ensure HTMLCollection is captured for multiple events
  • #720 - Fix take(n)
  • #725 - Fix querySelectorAll issue for IE8 compat
  • #727 - Fix sample laziness
  • #745 - Fix pausableBuffered
  • #763 - Fix do observer issues
  • controlled issue