13 Feb

Knockout Asynchronous Computed Observables

With its Observables and Computed Observables, Knockout provides some simple mechanisms for binding data values. However, when it comes to capturing results of asynchronous calls in variables, things become a little bit more complicated. Here is what the difficulties are and what can be done about them:

Observables, computed observables and their limitations

An observable is a special kind of object that can have subscribers. If the value of an observable changes, its subscribers are automatically notified about that changes. This is how we can declare observables with Knockout:

Now we can specify a function that computes a new value from these observables. This function is called a computed observable and its value is updated whenever any of the observables it depends on are changed:

The problem is that both observables and computed observables have to return a value synchronously. However, sometimes we might need to do asynchronous calls such as AJAX requests and sometimes we might even want to use a computed observable to represent the data we fetch with this AJAX request.

Capturing asynchronous results in an observable

In order to still be able to catch asynchronous results in an observable, we can declare a further observable queryResults and use a computed observable to do the AJAX request. The information obtained by the AJAX request can then be stored in queryResults:

Having the AJAX request wrapped inside a computed observable will ensure that it is called not just once, but every time one of the query parameters (pageIndex and sortColumn) changes its value.

Even though this solution works, it is not very nice that it requires a separate observable queryResults; instead it would be more desirable to emit the output directly from the computed observable.

Asynchronous Computed Observables

A common way of handling asynchronous operations in JavaScript are Deferreds – objects that allow adding callback functions to callback queues so that you will be notified when the result becomes available. So if we can get our computed observable to return a Deferred object to represent the AJAX request, our problem will be solved.

In order to achieve this, we create a wrapper function asyncComputed around a computed observable. The computed observable captures the output of the deferred value and uses the callback to transfer the output onto the observable result, which is returned directly by the asyncComputed.

So if we want to make an AJAX call as reaction to an observable changing its value, we simply need to pass the AJAX call as evaluator to the asyncComputed like this:

As we can see, the asyncComputed can be used in place of a regular computed observable, and its result will appear asynchronously after any of its dependencies change. So we finally got the solution we have been looking for.

Share this

Leave a reply