14
Deferreds and Promises

In CoffeeRun, your modular code has helped you avoid the dreaded “spaghetti code” that can easily happen when you mix event-handling (UI) code with your application’s internal logic.

Your modules interact via function arguments, also known as callbacks. Callbacks are a fine solution for situations in which you have code that only depends on a single, asynchronous step. Figure 14.1 shows a simplified version of one asynchronous flow from CoffeeRun.

Figure 14.1  Asynchronous flow for adding a coffee order

Asynchronous flow for adding a coffee order

What happens when you have many dependent asynchronous steps? One option is to nest lots of callbacks, but this quickly becomes unwieldy and dangerous. With a simplified version of your submit handler code that does extra error checking, that approach might look like this:

formHandler.addSubmitHandler(function (data) {
  try {
    myTruck.createOrder(function (error) {
      if (error) {
        throw new Exception(error)
      } else {
        try {
          saveOnServer(function (error) {
            if (error) {
              throw new Exception({message: 'server error'});
            } else {
              try {
                checkList.addRow();
              } catch (e2) {
                handleDomError(e2);
              }
            }
          })
        } catch (e) {
          handleServerError(e, function () {
            // Try adding the row again
            try {
              checkList.addRow();
            } catch (e3) {
              handleDomError(e3);
            }
          });
        }
      }
    });
  } catch (e) {
    alert('Something bad happened.');
  }
});

Promises, which you will learn about in this chapter, are a better solution. That same series of steps might be expressed as a chain of Promises like this:

formHandler.addSubmitHandler()
  .then(myTruck.createOrder)
  .then(saveOnServer)
  .catch(handleServerError)
  .then(checkList.addRow)
  .catch(handleDomError);

Promises provide a way to architect very complex asynchronous code in a manageable way, and in this chapter you will use them to simplify the architecture of CoffeeRun. Promises are a relatively new feature, but they are well supported in recent browsers, including Chrome.

In CoffeeRun, you are mainly interested in performing the next step if the current one succeeds without errors. Promises make this simple. Instead of relying on callback arguments, you will return Promise objects, which will let you decouple your modules even further.

Promises and Deferreds

Promise objects are always in one of three states: pending, fulfilled, or rejected (Figure 14.2).

Figure 14.2  Three states of a Promise object

Three states of a Promise object

Every Promise object has a then method that is triggered when the Promise becomes fulfilled. You can call then and pass it a callback; when the Promise is fulfilled, the callback is invoked and passed whatever value the Promise received when doing its asynchronous work.

You can also chain multiple then calls together. Instead of writing functions that accept and then invoke callbacks, it is better to return Promise objects and let the caller chain a then off of that Promise.

You are going to start with jQuery’s Deferred object, which works similarly to a Promise for simple use cases.

jQuery’s $.ajax methods (including $.post and $.get) return a Deferred. Deferred objects have methods that let you register callbacks for two of their states: fulfilled and rejected. You are going to start by updating RemoteDataStore so that it returns the Deferreds produced by jQuery’s Ajax methods. Later, you will modify your other modules to register callbacks with the Deferreds.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.114.28