Published: 23 May 2012
By: Jing Ding

jQuery Deferred/Promise objects untangle spaghetti-like asynchronous code.

Contents [hide]

Introduction

Introduced in jQuery 1.5, Deferred/Promise type is an implementation of CommonJS Promise/A interface. The new types change the way asynchronous methods are called. For example, $.ajax() now returns a Promise object, to which you can attach callbacks. Prior to version 1.5, you make ajax calls like this,

Since version 1.5, you can rewrite the above code like this,

So what's the big deal? Isn't it just another syntax sugar for consistency with jQuery's fluent style? No, it is not a simple syntax change. If it were just for the fluent syntax, it should have been introduced since version 1.0. It is a paradigm shift in asynchronous programming.

I am not going to repeat or rephrase the definition of Deferred/Promise, nor give syntactic usage examples out of context. You can get them from jQuery website, Deferred/Promise. If you are still in the dark after reading the official documentation, then try the following explanation within the context of asynchronous code examples. More specifically, I will show you how asynchronous callbacks make a simple for loop and an if…else branch like spaghetti, and how Deferred/Promise objects untangle the spaghetti code.

Loop example

The example repeats 5 tasks sequentially in a loop, and reports final result after the loop. Let's first look at its synchronous implementation. You may experiment with the code example at jsFiddle.

Here is the output.

Output

Step 1 finished.

Step 2 finished.

Step 3 finished.

Step 4 finished.

Step 5 finished.

All steps done.

Although dead simple, the example shows a clear-cut separation between the work logic and the control logic. The worker function, doTask, does not know or care anything about how it is called; while the main function focuses on execution flow.

Now let's make the worker function asynchronous.

The asynchronous version of doTask initiates a task, and returns immediately. The task will finish after a random delay. The asynchronicity distorts execution flow. The execution flow does not follow code flow any more. The final report is always executed first; and then the 5 steps are finished in random order. Below is the output of a typical run.

Output

All steps done.

Step 4 finished.

Step 2 finished.

Step 3 finished.

Step 1 finished.

Step 5 finished.

In order to restore the original execution flow using old-fashioned callbacks, the code flow has to be re-structured. There are two options to re-structure the code. The first option is to use nested callbacks:

Listing 1: http://jsfiddle.net/dingjing/prCDL/2/

Two observations for nested callbacks:

  1. The worker function is no longer independent of control logic. It needs to know what to do next.
  2. The main function is not scalable any more. It is trivial to scale the synchronous version to 100 steps or even 1 million steps. Try that on the nested callbacks!
  3. The other option is to use recursive callbacks:

Listing 2: http://jsfiddle.net/dingjing/YRZn7/2/

Now, the work logic and the control logic are completely mixed together. Although this version is shorter than the nested callback version, it is actually harder to READ the code to figure out what it does.

One way or the other, callbacks break the separation between the work logic and the control logic, mix them together, and make spaghetti-like code. If we add task dependency into the control logic, callbacks will make the code even more tangled, as shown in the next code example.

Branch example

In this example, the first task (doTask1) returns a random integer between 0 and 10. If the return value is greater than or equal to 5, then task 2 (addTask) is executed; otherwise, task 3 (multiplyTask) is executed. First, let's have a look at the synchronous version. Please note again the separation between work logic and control logic.

Listing 3: http://jsfiddle.net/dingjing/SLLCu/2/

Here is a sample output.

Output

Task 1 returned 6

addTask finished with 6

All tasks finished with 12

Next, let's look at the asynchronous version.

Listing 4: http://jsfiddle.net/dingjing/Zzq8F/2/

Once again, the work logic and the control logic are tangled all over the place. Just reading the code, are you able to figure out what it does without the hint from the synchronous version?

Now it's time to see how Deferred/Promise objects can untangle the spaghetti code.

Deferred/Promise untangle spaghetti code

First, the loop example.

Listing 5: http://jsfiddle.net/dingjing/sPBv6/3/

Then, the branch example.

Listing 6: http://jsfiddle.net/dingjing/aaaVT/1/

Please appreciate how Deferred/Promise objects restore the separation between the work logic and the control logic, making the code very much similar to their synchronous versions.

Paradigm shift

In old-fashioned callback paradigm, asynchronous methods are void black holes. The first time you call an asynchronous method, you pass the point of no return. You lose the control of code flow, giving it up to the asynchronous method.

In the new paradigm, asynchronous methods return Deferred/Promise objects. A Deferred/Promise object is an abstraction of an ongoing process. You can observe the status of the process, attach callbacks to be executed when the process is done or failed, or chain another process to the current process. Most importantly, an asynchronous method returns code flow to its calling method, so you are still in control.

Note

Technically, traditional asynchronous methods also return to their calling methods. However, those returns are meaningless in terms of code flow control.

Conclusion

jQuery's Deferred/Promise objects return asynchronous methods as observable processes, untangling spaghetti-like callbacks.

<<  Previous Article Continue reading and see our next or previous articles

About Jing Ding

Jing Ding is a Sr. Systems Consultant at the Ohio State University Medical Center. He is an Iron Speed MVP. His native language is C#.

This author has published 6 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Animating a Web Form using ASP.NET AJAX
In this article you will learn how to animate a webform using asp.net ajax.
Jquery Ajax
JQuery makes communicating with the server very, very easy. JQuery uses get(), getJSON(), and post(...
jQuery in Action 2nd edition: Queuing functions for execution
This article is taken from the book jQuery in Action, second edition. This segment shows how you can...
Book Review: Pro JavaScript Design Patterns
Brain Mains reviews Pro JavaScript Design Patterns.
Test120Jan
This is my custom article

You might also be interested in the following related blog posts


jQuery and ASP.NET Article Part 2 Posted read more
jQuery Intellisense in VS 2008 read more
jQuery Intellisense Updates from Microsoft read more
Inclusion of JavaScript Files read more
Download AjaxPro Beta with jQuery Support read more
Top
 
 
 

Discussion


Subject Author Date
placeholder All very clear, except... the core of the article Wagner Cateb 2/26/2014 1:10
RE: All very clear, except... the core of the article Jing Ding 2/27/2014 2:53
placeholder RE: All very clear, except... the core of the article Jing Ding 3/1/2014 9:20 AM

Please login to rate or to leave a comment.