Lesson Tuesday

In the last lesson, we used jQuery to wrap async code in a promise. However, we also could’ve chosen to instantiate a new ES6 Promise object and worked with that as well, just as we’ve done with an XMLHttpRequest object. In this lesson, we’ll take a look at how ES6 has implemented promises.

Once again, we’ll start with the code. We’ll modify our weather-interface.js file while our weather.html file will remain the same.

weather-interface.js
$(document).ready(function() {
  $('#weatherLocation').click(function() {
    let city = $('#location').val();
    $('#location').val("");

    let promise = new Promise(function(resolve, reject) {
      let request = new XMLHttpRequest();
      let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=[API-KEY-GOES-HERE]`;
      request.onload = function() {
        if (this.status === 200) {
          resolve(request.response);
        } else {
          reject(Error(request.statusText));
        }
      }
      request.open("GET", url, true);
      request.send();
    });

    promise.then(function(response) {
      body = JSON.parse(response);
      $('.showHumidity').text(`The humidity in ${city} is ${body.main.humidity}%`);
      $('.showTemp').text(`The temperature in Kelvins is ${body.main.temp} degrees.`);
    }, function(error) {
      $('.showErrors').text(`There was an error processing your request: ${error.message}`);
    });
  });
});

In the code snippet above, we create a new Promise using the following structure:

let promise = new Promise(function(resolve, reject) {
  resolve( //do this on resolution);
  reject(//do this on rejection);
});

We are passing in two parameters; resolve will determine what happens when the promise is resolved while reject will handle the promise if it’s rejected.

Because we’re solving this problem with JavaScript, not jQuery, we create a new XMLHttpRequest object here. We also use a new XMLHttpRequest method: onload(). onload() is called once the request is complete. Before, we used onreadystatechange; theoretically, we could still do something like this, right?

request.onreadystatechange = function() {
      if (this.readyState === 4 && this.status === 200) {
        //resolve here
      } else {
    //reject here
  }
}

Actually, this won’t work. onreadystatechange is called every time the readyState of our request changes. It will work its way from 0 to 4, but a promise can only be rejected once. The first time the readyState changes, our promise will be rejected and we’ll never get the result of our API call.

With onload(), we wait until the request is complete. If the response has a 200 status, we’ll resolve the promise, which will return the response from the request.

If the API call doesn’t have a 200 status, the promise will be rejected. We’ll call a new instance of JavaScript’s built-in Error class. The specific error will be the statusText of our request. (A quick reminder: statusText is a built-in prototype that can be called on a XMLHttpRequest object.)

Our promise also handles opening and sending the request. We now have an async API call wrapped inside a promise, waiting to be called.

We’ve built a promise from scratch. Promises have a number of prototypes, including the then() method. While it works in a similar fashion to jQuery’s then() method, note the differences in syntax. If the promise is resolved, we’ll parse the JSON and return the temperature and humidity.

If it’s rejected, we’ll take advantage of the Error object’s message prototype to return the error. For instance, if we submit a request without inputting a city, we’ll get the following: There was an error processing your request: Bad Request.

JavaScript’s Promise API exposes several useful prototype methods. For instance, let’s say that you have an application that needs to wait for the result of multiple API calls. We could do the following with Promise.all():

Promise.all(promise1, promise2, promise3);

Promise.all() wraps the enclosed promises into a single giant promise that only resolves after each of the included promises are resolved.

There are a number of other methods such as Promise.race() and Promise.catch(). Check out Mozilla’s documentation on promises to learn more.