github Reactive-Extensions/RxJS v2.3.22
RxJS version 2.3.22

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

This is a significant update from the previous supported release of v2.3.18 which contains a number of new pieces.

The major items in this release are:

  • Long Stack Traces Support
  • Tessel Support
  • More Backpressure Operators
  • TypeScript Definitions Updates
  • Documentation and Code Updates
  • More Examples

Long Stack Traces Support

When dealing with large RxJS applications, debugging and finding where the error occurred can be a difficult operation. As you chain more and more operators together, the longer the stack trace gets, and the harder it is to find out where things went wrong. This has been a request from the community for quite some time, so now your wish is our command. We took inspiration from the Q library from @kriskowal which helped us get started.

RxJS now comes with optional support for “long stack traces,” wherein the stack property of Error from onError calls is rewritten to be traced along asynchronous jumps instead of stopping at the most recent one. As an example:

var Rx = require('rx');

var source = Rx.Observable.range(0, 100)
  .timestamp()
  .map(function (x) {
    if (x.value > 98) throw new Error();
    return x;
  });

source.subscribeOnError(
  function (err) {
    console.log(err.stack);
  });

The error stack easily becomes unreadable and hard to find where the error actually occurred:

$ node example.js

  Error
  at C:\GitHub\example.js:6:29
  at AnonymousObserver._onNext (C:\GitHub\rxjs\dist\rx.all.js:4013:31)
  at AnonymousObserver.Rx.AnonymousObserver.AnonymousObserver.next (C:\GitHub\rxjs\dist\rx.all.js:1863:12)
  at AnonymousObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (C:\GitHub\rxjs\dist\rx.all.js:1795:35)
  at AutoDetachObserverPrototype.next (C:\GitHub\rxjs\dist\rx.all.js:9226:23)
  at AutoDetachObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (C:\GitHub\rxjs\dist\rx.all.js:1795:35)
  at AnonymousObserver._onNext (C:\GitHub\rxjs\dist\rx.all.js:4018:18)
  at AnonymousObserver.Rx.AnonymousObserver.AnonymousObserver.next (C:\GitHub\rxjs\dist\rx.all.js:1863:12)
  at AnonymousObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (C:\GitHub\rxjs\dist\rx.all.js:1795:35)
  at AutoDetachObserverPrototype.next (C:\GitHub\rxjs\dist\rx.all.js:9226:23)

Instead, we can turn on this feature by setting the following flag:

Rx.config.longStackSupport = true;

When running the same example again with the flag set at the top, our stack trace looks much nicer and indicates exactly where the error occurred:

$ node example.js
  Error
  at C:\GitHub\example.js:6:29
  From previous event:
  at Object.<anonymous> (C:\GitHub\example.js:3:28)
  From previous event:
  at Object.<anonymous> (C:\GitHub\example.js:4:4)
  From previous event:
  at Object.<anonymous> (C:\GitHub\example.js:5:4)

As you'll see our error did occur exactly at line 6 with throwing an error and only shows the user code in this point. This is very helpful for debugging, as otherwise you end up getting only the first line, plus a bunch of RxJS internals, with no sign of where the operation started.

This feature does come with a serious performance and memory overhead, however, If you're working with lots of RxJS code, or trying to scale a server to many users, you should probably keep it off. In development, this is perfectly fine for finding those pesky errors!

In a future release, we may also release support for a node.js environment variable so that you can set it and unset it fairly easily.

Tessel Support

RxJS has a mission to be supported on every JavaScript platform, ranging from node.js, to the browser, in the OS runtime, and even directly on hardware. To that point, we aimed to get RxJS supported on the Tessel board. There were several issues with RxJS that had to be addressed due to the following Tessel Runtime issues.

To overcome Issue 682, we implemented a naive version of Object.prototype.propertyIsEnumerable if it is missing. This also will overcome a bug in Safari 2 as well. In order to solve Issue 658, you can only use rx.lite or rx.lite.compat directly with the Tessel at this time of the release.

We now ship the blinky example for the Tessel using RxJS in our examples folder.

// Run with "tessel run blinky.js"

// Import the interface to Tessel hardware
var tessel = require('tessel');

// Must use lite compat due to https://github.com/tessel/runtime/issues/658
var Observable = require('../../dist/rx.lite').Observable;

// Set the led pins as outputs with initial states
// Truthy initial state sets the pin high
// Falsy sets it low.
var led1 = tessel.led[0].output(1);
var led2 = tessel.led[1].output(0);

Observable.interval(100)
  .subscribe(function () {
    console.log('first blinks');
    led1.toggle();
  });

Observable.interval(150)
  .subscribe(function () {
    console.log('second blinks');
    led2.toggle();
  });

We hope those issues get resolved soon so that you can use the entire RxJS. If you wish, you could also create a custom build of RxJS as well with fewer methods which would solve the issues.

More Backpressure Operators

In previous releases of RxJS, we have implemented some basic backpressure operators, whether lossy or lossless through pausable, pausableBuffered and controlled. In this release we took the idea of the controlled operator even further with two further specializations with "Stop and Wait" and "Sliding Window". Much of this work is derived work from Johann Laanstra in his BackPressureRx project.

Stop-and-wait

The most simple flow control algorithm is stop-and-wait. It works by simply producing a value and wait until is has been processed completely. Stop-and-wait is a special case of the Sliding Window protocol, which will be discussed later, where the window has size.

In the implementations of these flow control algortihms for RxJS we don’t have to take into account acknowledgments and damage of values, This allows us to simplify stop-and-wait by removing the need for an Automatic Repeat reQuest (ARQ) mechanism and CRC checks on the values.

works by default similar to stop-and-wait. The onNext call blocks until the value has been processed by the chain or until the value gets scheduled on a different scheduler. If there or no switches between scheduler in a chain, this means there will always be a single value in the chain at any moment. Using the controlled operator we can use the increased flexibility to also make he case with different schedulers work, by requesting only one value at a time.

Stop-and-wait has been implemented as the stopAndWait combinator on a ControlledObservable. It represents the most basic synchronous case, where a thread starts requesting items and those items are pushed on that same thread.

StopAndWaitObserver.prototype.next = function (value) {
  this.observer.onNext(value);

  var self = this;
  Rx.Scheduler.timeout.schedule(function () {
    self.observable.source.request(1);
  });
};

When an observer subscribes to the stopAndWait, it subscribes to the underlying ControlledObservable and attaches itself as the controller. It starts by requesting a single value and then every time a value has come to its onNext method, it asynchronously requests a new value. Multiple subscribers can be attached but there will only be a single controller active. The logic to do this can be seen in the subscribe method. As soon as all subscribers have been detached, the controller will also be detached. As you can see in the above code the observer is wrapped in a StopAndWaitObserver class. This class request the new value as soon as the current one has been processed by the queue, which can be seen in the next method.

An example of this in action is the following:

var source = Rx.Observable.interval(1000)
  .timestamp()
  .controlled();

source.stopAndWait().subscribe(function (x) {
  // Do something with the value
});

Sliding Window Protocol

A more advanced flow control algorithm is a Sliding Window. Sliding Window is a method of flow control in which a receiver gives a transmitter permission to transmit data until a window is full. When the window is full, the transmitter must stop transmitting until the receiver advertises a larger window. Sliding Window is the protocol used by TCP to do flow control. For the Sliding Window protocol we can perform the same optimizations as for the Stop-and-Wait protocol. RxJS does not have to take care of damaged or lost values.

We on the Rx team created a sliding window combinator based on the code for stopAndWait called windowed. RxJS wants to request a new value as soon as there is a slot available in the window, but instead of requesting a single value to begin with, RxJS requests multiple at the start, and thereby defining the window size that will be used by the observable. By using windowed(1), will gives us the stop-and-wait algorithm, which now could be simply implemented using the windowed operator.

WindowedObserver.prototype.next = function (value) {
  this.observer.onNext(value);

  this.received = ++this.received % this.observable.windowSize;
  if (this.received === 0) {
    var self = this;
    Rx.Scheduler.timeout.schedule(function () {
      self.observable.source.request(self.observable.windowSize);
    });
  }
};

The code for the WindowedObservable is almost identical to the StopAndWaitObservable in that the only difference is the window size. Now we can use this to request 10 at a time in our sliding window.

var source = Rx.Observable.interval(1000)
  .timestamp()
  .controlled();

source.windowed(10).subscribe(function (x) {
  // Do something with the value
});

TypeScript Definition Updates

The community is to thank for the TypeScript bindings that ship with RxJS. We on the RxJS team have a lot of gratitude towards @Igorbek, @PublicParadise, @danko-d and others who have helped us tremendously. The type definition files should be up to date modulo the new changes with the backpressure operators and perhaps some of the methods such as flatMap/selectMany and concatMap/selectConcat accepting Iterables as return values, like Array, Set, or Map.

Documentation and Code Updates

Documentation has also been improved in this release, many of it adding more examples for each project type, whether it is using React or some other framework.

For example, we now have better React frameworks that work with RxJS such as:

In addition, we are continuing to add more documentation to differentiate RxJS from other libraries. For example, here is a start on "Why RxJS versus Bacon.js" and will be adding more technical differences mapping between the two libraries soon, as well as others such as async.js, highland.js and others.

For documentation fixes, we'd like to thank the following for their efforts: @jayphelps, @juniorz, @scouten, @andrewsf, @sergi, @dziemid, @safareli, @mathbruyen, @RodEsp, @mmv, @jpmossin, @ReubenBond, @sebagomez and many others.

For code fixes, we'd like to thank the following for their hard work: @patrickkamin, @lukegb, @bparadie among others.

More Examples

One thing we pride ourselves on is our great set of examples on how to get started with RxJS.

The following examples have been added:

Don't miss a new RxJS release

NewReleases is sending notifications on new releases.