Deferreds and Promises: Structuring Your JavaScript Code with Ease (+ Ember.js Example)
tags: [“Promises”, “Deferred”, “JavaScript”, “Async Management”, “Ember.js”]
Promises are an innovative approach to managing asynchronous code in JavaScript. They provide a structured way to handle events and make your code more readable. In this blog post, we will explore the concept of Promises and Deferreds in JavaScript, using examples with jQuery and Ember.js.
What are Promises?
A Promise is an object that represents an event and its lifecycle. It starts in a pending state when it is called and transitions to a resolved or rejected state when the event is completed. In some cases, a Promise may stay in the pending state indefinitely and never resolve.
Promises are a new way of handling JavaScript events and offer a more readable and less quirky alternative. Currently, there are two main implementations of Promises in JavaScript: libraries that follow the Promises/A specification, and jQuery.
Introducing jQuery Promises
Let’s start by looking at the jQuery implementation of Promises, as it is widely used and readily available. jQuery provides an object called Deferred, which is essentially a Promise with additional methods to trigger its resolution or rejection. A Promise, on the other hand, is a read-only component of a Deferred.
Here is an example of creating a Promise using jQuery:
1 | var promise = $('div.alert').fadeIn().promise(); |
You can now add .done() and .fail() callbacks to handle the resolution or rejection of the Promise. Promises for animations are commonly used in jQuery 1.8, often with callbacks for progress.
Another example of using a Promise is with an AJAX call:
1 | var promise = $.get(url); |
A Deferred is created by the developer, and callbacks are added to it. The Deferred can be resolved using the .resolve() method, like this:
1 | var deferred = new $.Deferred(); |
The state of a Deferred can be changed using the .resolve() or .reject() methods. Once a Deferred is resolved or rejected, its state cannot be changed.
Callbacks can be attached to a Promise using the following methods:
1 | .done() // to be executed when the Promise is successfully resolved |
These callbacks can also be combined using the .then() method:
1 | promise.then(doneFunc, failFunc, alwaysFunc); |
These are just the basics of the jQuery implementation of Promises and Deferreds. Now, let’s look at some real-world examples.
jQuery Examples
Here are some examples of using Promises and Deferreds in jQuery:
- Executing a function and calling a callback when it’s finished:
1 | $.when(execution()).then(executionDone); |
- Processing elements in an array and calling a callback when all of them are completed:
1 | var data = [1,2,3,4]; // ids coming back from serviceA |
- A more complex example, fetching elements from an external resource and processing them:
1 | var data = []; // ids coming back from serviceA |
These examples demonstrate how Deferreds can be used to process a for loop and wait for the completion of all tasks before executing further code.
Ember.js Example
I often use Deferreds in combination with Ember.js. Here is an example of integrating Deferreds with Ember.js:
1 | App.DeferredHelper = { |
With Ember.js, you can use the DeferredHelper object and its methods to check if an array has elements or if a variable is set:
1 | $.when(App.DeferredHelper.arrayContainsElements('itemsController.content')) |
1 | $.when(App.DeferredHelper.variableIsSet('aVariable')) |
These examples demonstrate how Deferreds can be used in conjunction with Ember.js to handle asynchronous operations.
Other Libraries and Implementations
While we have focused on the jQuery implementation, there are other libraries available that provide Promises and Deferreds functionality, such as Q, RSVP.js, and when.js. These libraries have their own specialized implementations of Promises and Deferreds, offering similar functionalities.
Here is an example using the when.js library to process AJAX calls and handle the results using Promises:
1 | function processItem(item) { |
Conclusion
Promises and Deferreds provide a structured approach to managing asynchronous code in JavaScript. They offer a more readable and less error-prone way of handling events and structuring your code. Whether you choose to use the jQuery implementation or explore other libraries, Promises and Deferreds are powerful tools that can greatly improve the organization and readability of your JavaScript code.