github Reactive-Extensions/RxJS v2.3.14
RxJS version 2.3.14

latest releases: v4.1.0, v4.0.8, v4.0.7...
9 years ago

This release of RxJS is a minor release which followed 2.3.13, which was only a fix for Rx.spawn to ensure it was thoroughly tested.

This release contained the following:

  • Transducers Support
  • Adding Iterable Support to flatMap/seleectMany and concatMap /selectConcat

Transducers Support

Much like Language Integrated Query (LINQ), Transducers are composable algorithmic transformations. They, like LINQ, are independent from the context of their input and output sources and specify only the essence of the transformation in terms of an individual element. Because transducers are decoupled from input or output sources, they can be used in many different processes - collections, streams, observables, etc. Transducers compose directly, without awareness of input or creation of intermediate aggregates. There are two major libraries currently out there, Cognitect's transduce.js and James Long's transduce-js which are both great for getting high performance over large amounts of data. Because it is collection type neutral, it is a perfect fit for RxJS to do transformations over large collections.

The word transduce is just a combination of transform and reduce. The reduce function is the base transformation; any other transformation can be expressed in terms of it (map, filter, etc).

var arr = [1, 2, 3, 4];

arr.reduce(
  function(result, x) { return result.concat(x + 1); }, []);

// => [ 2, 3, 4, 5 ]

Using transducers, we can model the following behavior while breaking apart the map aspect of adding 1 to the concat operation, adding the seed and then the "collection" to transduce.

var arr = [1, 2, 3, 4];

function increment(x) { return x + 1; }
function concatItem(acc, x) { return acc.concat(x); }

transduce(map(increment), concatItem, [], arr);

// => [ 2, 3, 4, 5 ]

Using Cognitect's transduce.js library, we can easily accomplish what we had above.

var t = transducers;

var arr = [1, 2, 3, 4];

function increment(x) { return x + 1; }

into([], t.comp(t.map(increment)), arr);

// => [ 2, 3, 4, 5 ]

We can go a step further and add filtering as well to get only even values.

var t = transducers;

var arr = [1, 2, 3, 4];

function increment(x) { return x + 1; }
function isEven(x) { return x % 2 === 0; }

into([], t.comp(t.map(increment), t.filter(isEven)), arr);

// => [ 2, 4 ]

Since it works so well using Arrays, there's no reason why it cannot work for Observable sequences as well. To that end, we have introduced the transduce method which acts exactly like it does for Arrays, but for Observable sequences. Once again, let's go over the above example, this time using an Observable sequence.

var t = transducers;

var source = Rx.Observable.range(1, 4);

function increment(x) { return x + 1; }
function isEven(x) { return x % 2 === 0; }

var transduced = source.transduce(t.comp(t.map(increment), t.filter(isEven)));

transduced.subscribe(
  function (x) { console.log('Next: %s', x); },
  function (e) { console.log('Error: %s', e); },
  function ()  { console.log('Completed'); });

// => Next: 2
// => Next: 4
// => Completed

Note that this above example also works the same with transducers.js as well with little to no modification. This example will in fact work faster than the traditional LINQ style (as of now) which most use currently.

var source = Rx.Observable.range(1, 4);

function increment(x) { return x + 1; }
function isEven(x) { return x % 2 === 0; }

var transduced = source.map(increment).filter(isEven);

transduced.subscribe(
  function (x) { console.log('Next: %s', x); },
  function (e) { console.log('Error: %s', e); },
  function ()  { console.log('Completed'); });

// => Next: 2
// => Next: 4
// => Completed

This opens up a wide new set of possibilities making RxJS even faster over large collections with no intermediate Observable sequences.

Iterable Support for flatMap/seleectMany and concatMap /selectConcat

In order to maintain parity with the Reactive Extensions for .NET, RxJS has now added support for Arrays and ES6 iterables (Map, Set, Generator). So now, it is possible to do the following:

/* Using an array */
Rx.Observable.of(1,2,3)
  .flatMap(
    function (x, i) { return [x,i]; },
    function (x, y, ix, iy) { return x + y + ix + iy; }
  );

var subscription = source.subscribe(
    function (x) {
        console.log('Next: ' + x);
    },
    function (err) {
        console.log('Error: ' + err);
    },
    function () {
        console.log('Completed');
    });

// => Next: 2
// => Next: 2
// => Next: 5
// => Next: 5
// => Next: 8
// => Next: 8
// => Completed

We can also have that for a Set as well:

/* Using an array */
Rx.Observable.of(1,2,3)
  .flatMap(
    function (x, i) { return new Set[x,i]; },
    function (x, y, ix, iy) { return x + y + ix + iy; }
  );

var subscription = source.subscribe(
    function (x) {
        console.log('Next: ' + x);
    },
    function (err) {
        console.log('Error: ' + err);
    },
    function () {
        console.log('Completed');
    });

// => Next: 2
// => Next: 2
// => Next: 5
// => Next: 5
// => Next: 8
// => Next: 8
// => Completed

And finally, we could also have it for an ES6 generator as well:

/* Using an array */
Rx.Observable.of(1,2,3)
  .flatMap(
    function (x, i) { return function* () { yield x; yield i; }(); },,
    function (x, y, ix, iy) { return x + y + ix + iy; }
  );

var subscription = source.subscribe(
    function (x) {
        console.log('Next: ' + x);
    },
    function (err) {
        console.log('Error: ' + err);
    },
    function () {
        console.log('Completed');
    });

// => Next: 2
// => Next: 2
// => Next: 5
// => Next: 5
// => Next: 8
// => Next: 8
// => Completed

Don't miss a new RxJS release

NewReleases is sending notifications on new releases.