Giving DataStore a Promise

By returning Deferreds from RemoteDataStore’s methods, you have a flexible way to use the data sent back from the server.

But you may have noticed that RemoteDataStore’s methods now stray far away from how DataStore’s methods work. If you were to swap a regular DataStore back in, you would see that it no longer works with your application (Figure 14.6).

Figure 14.6  Uh oh. DataStore is no longer compatible

Uh oh. DataStore is no longer compatible

In Figure 14.6, you can see that instantiating a Truck with a regular DataStore throws errors and fails to work correctly with the UI. CoffeeRun expects a Promise-based DataStore in order to function correctly.

To remedy this situation, you are going to change DataStore’s four methods so that they return Promises.

jQuery’s Deferred objects have treated you well. However, because DataStore is not using the jQuery $.ajax methods you have been using to access Deferreds, you will need to use the native Promise constructor to create and return Promises.

Creating and returning Promises

In datastore.js, you are going to update the add method. But first, create a Promise variable and assign it the value window.Promise. While not absolutely necessary, it is a good idea to continue this pattern of importing anything from the global scope that you will need inside of your module.

Inside the add method, create a new variable called promise. Assign it a new instance of Promise. Make sure to return the promise variable at the end of add.

(function (window) {
  'use strict';
  var App = window.App || {};
  var Promise = window.Promise;

  function DataStore() {
    this.data = {};
  }

  DataStore.prototype.add = function (key, val) {
    this.data[key] = val;
    var promise = new Promise();

    return promise;
  };
...

The Promise constructor needs a function argument. Pass it an anonymous function that accepts two function arguments, resolve and reject.

...
  DataStore.prototype.add = function (key, val) {
    this.data[key] = val;
    var promise = new Promise(function (resolve, reject) {
    });

    return promise;
  };
...

When the Promise does its work, it will invoke the anonymous function argument and pass it two values: resolve and reject. The resolve function is invoked to change the state of the Promise object to fulfilled. The reject function is invoked to change the state of the Promise object to rejected.

Next, move the data storage line (this.data[key] = val;) down into the body of the anonymous function. To make sure that this.data correctly refers to the DataStore’s data instance variable, bind the anonymous function to this.

...
  DataStore.prototype.add = function (key, val) {
    this.data[key] = val;
    var promise = new Promise(function (resolve, reject) {
      this.data[key] = val;
    }.bind(this));

    return promise;
  };
...

Resolving a Promise

At the very end of the anonymous function, invoke resolve with no argument.

...
  DataStore.prototype.add = function (key, val) {
    var promise = new Promise(function (resolve, reject) {
      this.data[key] = val;
      resolve(null);
    }.bind(this));

    return promise;
  };
...

Why use null as the argument? adding a value to the DataStore does not produce a value, so there is nothing for it to resolve to. When you need to explicitly return a non-value you should use null. (You could also use resolve(val) to give the next function in the chain access to the freshly stored value. For CoffeeRun, this is not necessary, and therefore not included as part of the example.)

Promise-ifying the other DataStore methods

You could manually update the other three methods using this same pattern of code. But instead of retyping all that code, create a helper function called promiseResolvedWith to create a Promise, resolve it, and return it. Update DataStore.prototype.add to use this helper.

...
  function DataStore() {
    this.data = {};
  }

  function promiseResolvedWith(value) {
    var promise = new Promise(function (resolve, reject) {
      resolve(value);
    });
    return promise;
  }

  DataStore.prototype.add = function (key, val) {
    var promise = new Promise(function (resolve, reject) {
      this.data[key] = val;
      resolve(null);
    }.bind(this));

    return promise;
    return promiseResolvedWith(null);
  };
...

promiseResolvedWith is a reusable form of the Promise code you wrote in the add method. It accepts a parameter called value, creates a new variable named promise, and assigns it to a new instance of Promise. It passes an anonymous function to the Promise constructor that accepts two arguments: resolve and reject. Inside the anonymous function, you invoke resolve and pass it the value argument.

In promiseResolvedWith, you do not need to bind the function argument to this, as there are no references to this that need to be maintained.

Update the other methods to use promiseResolvedWith. Pass get and getAll the value you were returning in the non-Promise version. Pass null to remove.

...
  DataStore.prototype.get = function (key) {
    return this.data[key];
    return promiseResolvedWith(this.data[key]);
  };

  DataStore.prototype.getAll = function () {
    return this.data;
    return promiseResolvedWith(this.data);
  };

  DataStore.prototype.remove = function (key) {
    delete this.data[key];
    return promiseResolvedWith(null);
  };
...

Finally, update main.js to use a DataStore instead of a RemoteDataStore.

...
  var remoteDS = new RemoteDataStore(SERVER_URL);
  var webshim = window.webshim;
  var myTruck = new Truck('ncc-1701', remoteDS); new DataStore());
  window.myTruck = myTruck;
...

After making these changes, save your code and take CoffeeRun for another spin. You should see that it works correctly using DataStore, but makes no Ajax requests (Figure 14.7).

Figure 14.7  CoffeeRun is done!

CoffeeRun is done!

CoffeeRun has taken you on quite a journey! Along the way, you wrote some pretty serious JavaScript using IIFEs, callbacks, and Promises. You also got a taste of jQuery, which you used to manipulate DOM elements and communicate with a RESTful web service.

It is time to part ways with CoffeeRun and move on. The next app, Chattrbox, is a full-stack chat application. You will not only create the front-end code but also write the server. Do not worry if this is your first server application. You will still be using JavaScript, just not for the browser. Get ready to work with Node.js!

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

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