One common approach is that the method requires a single callback function in addition to its normal parameters. The called function will then invoke the callback function with an error as the first parameter, or a result as the second parameter. It is up to the callback function to determine whether it received an error or not.
The following contrived example shows how the
sendMsg function will invoke the callback and pass an error message or success result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
As mentioned before there are other common ways to do callbacks such as requiring separate success and error handling functions, or using objects with
onFailure methods. However, the solution is similar regardless of the callback pattern followed so the rest of this article will use the single callback function approach above as the example.
TypeScript, Observables and callbacks
1 2 3 4
This is all fine and works ok but I don’t want the clients of my code to have to pass a callback handler. What I really want is to return an Observable to my clients. I can achieve this as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
However the bit on
line 6 where we check for the error is a bit tedious. I will have to duplicate this all over the place and I don’t necessarily know what to do with the error. In most cases I will just send it along for the client to deal with.
To get rid of the error handling duplication I write a function to take the subject, success and optional error handler functions and return a callback function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
CallbackFunction cleans the method signature up a bit and makes things a bit easier to read.
The returned callback function checks the error and, if an error handler was provided, applies it before calling
error on the subject
(line 5). If no error is provided to the callback function then it will call
next on the subject to pass the valid result on to the observers.
This means that I can now rewrite the send message code as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13
This is much better since I don’t have to call
error on the subject and I don’t have to check for the error anymore. There is also much less code because I no longer have to explicitly handle the error. It can be fully delegated to the observers of the subject.
However, this still not perfect. I will be duplicating the
Observable creation lines everywhere. It also looks a bit weird to be creating a Subject and passing it on to another function.
I can get rid of the statements on
lines 3 and 12 above by writing another function which will return the Observable, relieving me from creating the subject explicitly.
Consider the following snippet:
1 2 3 4 5 6 7 8
Here I add another function
exec which will create a subject, turn the subject into a handler using
subToHandler defined earlier, apply the function provided as first parameter and then return an observable.
Note that I create the observable on
line 4 before applying the function
fn. This is important since subject will only notify its subscribers of changes after the time they subscribed.
Line 6 wraps the call to the function
fn in a timeout to handle the case where
fn doesn’t actually call the callback function asynchronously.
You’ll also notice that the first parameter to exec,
fn, is a function which takes a
Consider the following rewrite of the
1 2 3 4 5 6 7 8 9 10
Here I effectively partially applied the original
sendJS.sendMsg function by closing over the value of the first argument,
message, and returning a new function which takes only a callback function as parameter. This allows the
exec function to create the appropriate callback function, using
subToHandler and pass it to the partially applied