Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Introduction to the Reactive Extensions for JavaScript – Error Handling Part I

We’ve covered a bit recently with conditional and looping operators on the Reactive Extensions for JavaScript, but I want to step back just a minute and cover exception handling.  This post will cover how we can compensate for errors as they happen in several ways and will largely follow Bart de Smet’s post on the same topic, but instead of covering the Interactive Extensions, we’ll stick primarily in JavaScript.

Before we get started, let’s get caught up to where we are today:

 

Error Handling

When writing safe programs, we have to be mindful of exception handling.  Typically for imperative code we have try/catch/finally blocks which allow us to try a certain behavior, compensate for exceptions and do any cleanup that is necessary.

try {
    // do something
}
catch(exception) {
    // handle error
}
finally {
    // clean up
}

When it comes to asynchronous programming, the job becomes a bit harder.  How do we reliably do exception handling that doesn’t litter our codebase during each and every callback?

doAsyncAction1(data, function(result1) {
    // Handle exception here?
    
    doAsyncAction2(result1, function(result2) {
        // What about here?
        
        // What about more callbacks?
    });
});

Alternatively, some might have separate callback handlers for exceptions which further muddies the waters:

doAsyncAction1(data, 
    function(result1) {
    
        doAsyncAction2(result1, 
            function(result2) {
    
            },
            function(error2) {
                // handle this error
            });
    },
    function(error1) {
        // Handle it way down here
    });

With the Reactive Extensions for JavaScript, we have some mechanisms at our disposal for error handling and compensation.  Say for example, we have a safeDivide method which instead of producing infinity as the result of a divide by zero, instead we throw an exception.

function safeDivide(dividend, divisor) {
    var result = dividend / divisor;

    if (!isFinite(result)) {
        throw "Cannot divide by zero";
    }

    return result;
}

How can we use the Reactive Extensions to compensate for any such exceptions that happen?  Using our knowledge from previous posts, we’ll not only handle the OnNext part of our Observer, but also the OnError as well.  Let’s walk through a simple example of using our safeDivide.

var array1 = [3, 2, 1, 0];

Rx.Observable.FromArray(array1)
    .Select(
        function (next) {
            return safeDivide(100, next);
        })
    .Subscribe(
        // OnNext
        function (next) {
            $("<p/>").html(next).appendTo("#results");
        },
        
        // OnError
        function (err) {
            $("<p/>").html("Error: " + err).appendTo("#results");
        });

From this, we’ll get the following results in our web page:

33.333333333333336
50
100
Error: Cannot divide by zero

When the Select method above hits the condition where the exception is thrown, our observable sequence calls OnError handler on our observer and then immediately quits.  In this post, we’ll go over some of the compensation techniques outside our this standard OnError handler we have above.

Before we do so, let’s cover one more operator that will help us later on in the post, which is the ability to have the observable sequence throw an exception via the Throw function.  The Throw operator creates an observable sequence, when subscribed to, will call OnError with the given exception.

// exception : The exception to throw
// returns : Observable

Rx.Observable.Throw = function(
    exception);

We can see this in action by simply passing in a message such as the following:

Rx.Observable.Throw("oh noes!").Subscribe(
    function() { },
    function(msg) { alert(msg); }); // Shows oh noes!

Having seen that, let’s move onto our first compensation…

Catching the Exception and Moving On

The first operator we’ll cover is the Catch operator.  This operator allows us to continue an observable sequence that is terminated by an exception with the next observable sequence.  We have two overloads of the Catch as defined below with one being an instance method on the observable sequence and the other is a static method which takes an array of observable sequences and an optional scheduler.

// obs : varargs array of observable sequences
// returns : Observable

Rx.Observable.prototype.Catch = function(
    obs1, obs2, obs3, ...);

// items : Observable[]
// scheduler : an optional scheduler
// returns : Observable

Rx.Observable.Catch = function(
    items,
    scheduler);

The first version is much like an imperative version of a try/catch block which allows us to compensate and compose our workflows.  Now, let’s say you had an observable sequence that can cause the OnError to be fired like the following code will:

var couldThrow = Rx.Observable.FromArray([1, 2])
 	.Concat(Rx.Observable.Throw("oh noes!"))

What we can do to compensate is use the Catch function to continue on with the next sequence so that we end up with the numbers 1-5 printed on the screen where the last three values were from the compensation sequence.

couldThrow.Catch(Rx.Observable.FromArray([3, 4, 5]))
    .Subscribe(
        function (next) {
            $("<p/>").html(next).appendTo("#results");
        });

Just as well, we could just chain together sequences with compensations.  Below, I have an example of chaining together some values, exceptions and compensation values which will yield me once again the sequence of 1 through 5.

 var couldThrow = Rx.Observable.FromArray([1, 2])
    .Concat(Rx.Observable.Throw("oh noes!"))
    .Catch(Rx.Observable.FromArray([3, 4]))
    .Concat(Rx.Observable.Throw("not again!"))
    .Catch(Rx.Observable.Return(5));

couldThrow.Subscribe(
    function (next) {
        $("<p/>").html(next).appendTo("#results");
    });

The second version of the Catch operator allows us to have an array of observable sequences which allows us to compensate for sequences until no more errors occur.  Let’s take a look at an example of using this below.  What will be printed on the screen?

var exn = Rx.Observable.Throw("yup yup!");
var couldThrow = Rx.Observable.Catch([
    Rx.Observable.FromArray([1,2]).Concat(exn),
    Rx.Observable.FromArray([3,4]).Concat(exn),
    Rx.Observable.Return(5),
    Rx.Observable.Return(6)]);

couldThrow.Subscribe(
    function (next) {
        $("<p/>").html(next).appendTo("#results");
    });

If you guessed once again, the numbers 1 through 5, you would be correct.  Why?  The answer is simply that once 5 was yielded to us, there was no compensation needed, so 6 was not yielded.  Had the sequence which yielded 5 also thrown an exception, then I would have yielded 6.

And Finally…

Now that we’ve covered the Catch part of the equation, how about cleaning up resources at the end of our workflow?  How can the Reactive Extensions help us here?  Through the use of the Finally operator, we’re able to do just that.  The signature that follows shows that this takes a function with no parameters and has no return value. 

// finallyAction : () -> ()
// returns : Observable

Rx.Observable.prototype.Finally = function(
    finallyAction);

Let’s look at a regular workflow where we start with an array of 1 and 2.  Then we’ll add a Finally function to indicate that we are complete.  This will print out 1, 2 and then Finished!

Rx.Observable.FromArray([1, 2])
    .Finally(
        function() {
            $("<p/>").html("Finished!").appendTo("#results");
        })
     .Subscribe(
        function (next) {
            $("<p/>").html(next).appendTo("#results");
        });

How about we mix this up a little bit and show a bit more advanced scenario?  Let’s walk through the code in pseudocode before we begin.  The idea is that we yield the first two numbers and then have an exception thrown.  We then will print out “Finished”, followed by the outer catch yielding the next three values. 

try {
    try {
        yield 1;
        yield 2;
        throw "y'arr!";
    } 
    finally {
        print "Finished!";
    }
}
catch(exception) {
    yield 3;
    yield 4;
    yield 5;
}

The overall result should yield us: 1, 2, Finished, 3, 4, 5.  Let’s look at how that might be done using the Reactive Extensions for JavaScript.

Rx.Observable.FromArray([1, 2])
    .Concat(Rx.Observable.Throw("y'arr!"))
    .Finally(
        function() {
            $("<p/>").html("Finished!").appendTo("#results");
        })
    .Catch(Rx.Observable.FromArray([3,4,5]))
    .Subscribe(
        function (next) {
            $("<p/>").html(next).appendTo("#results");
        });

There’s more to cover here including more cleanup routines and compensation that we’ll get to in the next post including Using, OnErrorResumeNext and Retry.

Conclusion

Dealing with asynchronous programming has been in the forefront of many minds in the JavaScript community.  At JSConf, there were several examples of frameworks trying to get around the idea of callbacks and instead lean more towards composition.  By utilizing the Reactive Extensions for JavaScript, we’re able to compose together asynchronous and event-based operations together and transform the results in interesting ways.

When we start creating more advanced workflows through the Reactive Extensions, we also need ways of handling errors as well.  We have the ability do handle errors and compensate as they happen through a rich set of operators including Catch, Finally, Using, OnErrorResumeNext, Retry and more.

So with that, download it, and give the team feedback!

This entry was posted in Event-based Porgramming, JavaScript, JSConf, Reactive Framework. Bookmark the permalink. Follow any comments here with the RSS feed for this post.