JavaScript Tutorial Series - Promises




A promise is used when making calls to a process that will take a while to execute. Instead of hanging the application and waiting for the call to return, a promise is used. The promise tells the calling function, this could take a while, I'll send you back the result when it's done.
The calling function then continues on with the rest of the program.
When the long running call is done, the promise will send back the result to the caller. The caller then takes the result and does what it needs to with it.
Examples of calls to long running processes include rest api calls, file uploads and downloads, timeouts, or complex mathematical calculations.

The following is an example of a function that calls a timeout and returns a promise. When the timeout is finished, the promise sends back the result. The result could be a successful response or an error.


function examplePromise() {
    return new Promise((resolve, reject) => {
        setTimeout( function() {
            const anAnswer = "All done";
            resolve(anAnswer);
        }, 5000);
    });
}


This example uses a timeout to return after waiting 5 seconds. When the timeout is done, the resolve function is used to send the response back to the calling function.
If an error occurs, reject() would be used instead of resolve() to tell the caller something went wrong.

This function would be called like this:


examplePromise()
    .then((response) => {
        console.log('Success: ' + response);
    }
    .catch((error) => {
        console.log('Something went wrong: ' + error);
    }
    .finally(() => {
        console.log('Always do something');
    }

The then function will execute when resolve is called when the long running process is done.
The catch function will execute when reject is called from the long running process.
The finally function is optional. If defined, it will always execute when the long running process is done. It doesn't matter if resolve or reject was called. It will still execute.


Implementation:




For this tutorial implementation, open up the Weather.js file and add the bolded lines below:


js/modules/Weather.js:



class Weather {

    // Constructor
    constructor() {
    };

    getLocation() {

        return new Promise((resolve, reject) => {
            let url = 'https://ipinfo.io/json';
            let options = {
                mode : 'cors'
            };
            setTimeout( function() {
                resolve({});
            }, 5000);      
        });   
    
    };

    getWeather(coordinates) {

        return new Promise((resolve, reject) => {
          let options = {
              url: 'https://api.openweathermap.org/data/2.5/weather?lat=' + coordinates[0] +
                '&lon=' + coordinates[1] + '&appid=ENTER_YOUR_OPENWEATHERMAP_API_KEY_HERE',
              setRequestHeader: false,
              async: true
          };
          
          setTimeout( function() {
              resolve({});
          }, 5000);      
        });   
    
    }  
}

export default Weather;


These lines return a promise and will be resolved when a REST API is finished. The REST API implementation will be done in the next tutorial post.


Also edit the init function of js/javascript_tutorials.js to include the highlighted lines:




// JavaScript Tutorial

/*
 * This file will add JavaScript
 * to a website.
 */
import TemperatureConverter from "./modules/TemperatureConverter.js";
import Weather from "./modules/Weather.js";

(function() {
  let doc = document;
  let defaultLocation = [-86.7816, 36.1627]; // longitude, latitude

  function setWeather(data) {
    if (data) {
      let temp = Math.round(data.main.temp);
      try {
        let fahrenheit = TemperatureConverter.convertCelsiusToFahrenheit(temp - 273);
        console.log("Fahrenheit temperature: " + fahrenheit);
      } catch (error) {
        console.log("Error setting weather: " + error.message);
      }
    }
  }

  function init() {

    let weather = new Weather();
    weather.getLocation()
    .then((location, error) => {
       let coordinates = defaultLocation;
      weather.getWeather(coordinates)
      .then((weatherData, error) => {

      });
    });


    let locationStr = "";
    for (let i = 0, num = defaultLocation.length; i < num; i++) {
      locationStr += defaultLocation[i];
      if (i === 0) {
        locationStr += ", ";
      }
    }

    console.log("Setting weather for location: " + locationStr);

    setWeather({ main: { temp: 30 } });
  }

  init();
})();


These lines call the weather functions which return a promise. The next tutorial post will use the response returned from the promise.


For completeness, the other files in this tutorial are as follows:

index.html:



<html>
  <head>
    <link rel="stylesheet" href="css/style.css"/>
  </head>

  <body>
    <header>
      <nav>

      </nav>

      <article id="toolbar">
        <article id="currentWeather" class="text-center">
          <section id="location">
          </section>
          <section id="weatherTemperature">
            <span id="temperatureValue"></span>
            <span id="degreeSymbol">°</span>
            <span id="temperatureUnits"></span>
          </section>
          <section id="weatherDescription">
          </section>
          <img id="weatherIcon">                
          </img>
        </article>          
      </article>

    </header>

    <main></main>

    <footer></footer>

    <script src="js/javascript_tutorial.js" type="module"></script>
  </body>
</html>



js/modules/TemperatureConverter.js:



class TemperatureConverter {
  
    static convertKelvinToCelsius(kelvin) {
        if (typeof kelvin !== 'number') {
            throw 'Kelvin value is not a number';
        }
        return Math.round(kelvin - 273);
      }
    
      static convertCelsiusToFahrenheit(celsius) {
        if (typeof celsius !== 'number') {
            throw 'Celsius value is not a number';
        }
        return Math.round((celsius * (9/5)) + 32);
      };
    
      static convertFahrenheitToKelvin(fahrenheit) {
        if (typeof fahrenheit !== 'number') {
            throw 'Fahrenheit value is not a number';
        }
        return Math.round(((5/




export default TemperatureConverter;




css/style.css:




header nav {
  height: 10vh;
  border-bottom: 1px solid darkgray;
}

header #toolbar {
  height: 5vh;
  border-bottom: 1px solid darkgray;
}

main {
  height: 72vh;
  border-bottom: 1px solid darkgray;
}

footer {
  height: 10vh;
  border-bottom: 1px solid darkgray;
}



You should see the following in the browser console when loading the index.html file:

Setting weather for location: -86.7816, 36.1627
javascript_tutorial.js:19 Fahrenheit temperature: -405


Note, the files will need to be loaded onto a web server. If running them locally in Chrome, you may get a CORS error.


The JavaScript tutorial series starts with this post.


(paid links)

More JavaScript






Comments