Lesson Monday

Now that we've learned about promises, we're ready to update our weather API code to use one. We will be using the same code that we used during the prework - we'll only need to make changes in one file to incorporate promises in our project. Here is the code up to this point:


Example GitHub Repo for Project

The only file we'll need to update is main.js. We'll start by providing the code and then walking through the changes.

src/main.js
import $ from 'jquery';
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import './css/styles.css';

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

// New code begins here.

    let promise = new Promise(function(resolve, reject) {
      let request = new XMLHttpRequest();
      const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.API_KEY}`;
      request.onload = function() {
        if (this.status === 200) {
          resolve(request.response);
        } else {
          reject(request.response);
        }
      }
      request.open("GET", url, true);
      request.send();
    });

    promise.then(function(response) {
      const 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.`);
      $('.showErrors').text("");
    }, function(error) {
      $('.showErrors').text(`There was an error processing your request: ${error}`);
      $('.showHumidity').text("");
      $('.showTemp').text("");
    });
  });
});

Now let's break out the new code:

src/main.js
    let promise = new Promise(function(resolve, reject) {
      let request = new XMLHttpRequest();
      const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.API_KEY}`;
      request.onload = function() {
        if (this.status === 200) {
          resolve(request.response);
        } else {
          reject(request.response);
        }
      }
      request.open("GET", url, true);
      request.send();
    });

    promise.then(function(response) {
      const 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.`);
      $('.showErrors').text("");
    }, function(error) {
      $('.showErrors').text(`There was an error processing your request: ${error}`);
      $('.showHumidity').text("");
      $('.showTemp').text("");
    });

In the code snippet above, we take our previous code that creates and sends an XMLHttpRequest object and wrap it in a promise:

src/main.js
let promise = new Promise(function(resolve, reject) {
  let request = new XMLHttpRequest();
  const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.API_KEY}`;
  request.onload = function() {
    if (this.status === 200) {
      resolve(request.response);
    } else {
      reject(request.response);
    }
  }
  request.open("GET", url, true);
  request.send();
});

As we learned in the last lesson, we need to determine when a promise is resolved or rejected:

// We use resolve() and reject() to determine whether a promise should be resolved or rejected.

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

Our updated code already has a conditional so we just have to make a few small changes to handle resolving and rejecting our promise:

src/main.js
let request = new XMLHttpRequest();
const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.API_KEY}`;
request.onload = function() {
  if (this.status === 200) {
    resolve(request.response);
  } else {
    reject(request.response);
  }
}
request.open("GET", url, true);
request.send();

Also note that we use an event handler called onload with our XMLHttpRequest object instead of the property onreadystatechange. This event handler is yet another very convenient aspect of XMLHttpRequest objects. While we can continue to use onreadystatechange as well, using onload is a little bit more concise because we no longer have to specify a readyState of 4. Also, it will only be triggered once (when the response has loaded), and not every time the readyState changes. Why didn't we learn about onload right away when we first started working with XMLHttpRequest objects? Well, it's important to know about the different states of an XMLHttpRequest object. Now that we do, we can just use onload if we know we are just waiting for the request to load.

In the example above, we want the promise to resolve if this.status is equal to 200. If the API call doesn't have a 200 status, the promise will be rejected. We still want to return the request.response. Note that the response from the API call will look different because the API call failed.

As we can see, we didn't need much new code to incorporate a promise. Once again, that's because a promise is just an object with a couple of methods and functionality for us to determine whether it should be resolved or rejected.

Now let's look at the code for handling our promise:

src/main.js
promise.then(function(response) {
  const 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.`);
  $('.showErrors').text("");
}, function(error) {
  $('.showErrors').text(`There was an error processing your request: ${error}`);
  $('.showHumidity').text("");
  $('.showTemp').text("");
});

In the last lesson, we discussed how Promise.prototype.then() takes two arguments. Both are callback functions. The first argument is a function that should run if the promise is resolved. As we can see, this function parses the API response's body and then we use jQuery to reveal the humidity and temperature.

The second argument is a function that handles a rejected promise. In this case, we just show an error message and clear any prior text in the DOM regarding temperature and humidity.

By the way, the code above could use a little cleanup! We'll do that in a few lessons when we separate our logic into business and UI files.

As we can see, it didn't take much work at all to incorporate a promise in our code. They're really nice to work with - and they can make working with complex async code much easier.


Example GitHub Repo for API Project with Promises

Lesson 16 of 29
Last updated more than 3 months ago.