Skip to content

Instantly share code, notes, and snippets.

@Kotauror
Last active March 1, 2018 18:50
Show Gist options
  • Save Kotauror/d1268e80e8ad7648f2235bdc297c06e7 to your computer and use it in GitHub Desktop.
Save Kotauror/d1268e80e8ad7648f2235bdc297c06e7 to your computer and use it in GitHub Desktop.
Promise object in JS

Promise object in JS

This note is my attempt at explaining the idea of a promise object in JS.

Learning javascript as the second language, right after Ruby, is sometimes hard, as the path from zero to JS-hero is full of new - unknown to Ruby - concepts. One of them is a promise object that I happened uppon while creating my first end-to-end JS application.

Background

For an MVP I was supposed to write an application which:

  • allows user to add posts (listings) on the website,
  • and display the listings on the website,

so basically the first two steps of the CRUD cycle.

Tools

  • Node.js, express.js, sequelizer, postgres.

Relevant code

  • Listings controller

This file contains two CRUD methods for the listing model, one to create a record in the database and one for retrieve all of the records.

const Listing = require('../models').Listing;

module.exports = {
  create(req, res) {
    return Listing
      .create({
        name: req.body['listingname'],
        location: req.body['listinglocation'],
        description: req.body['listingdescription'],
        price: req.body['listingprice']
      })
  }, //I've used body-parser to get the data from a html form

  list(req, res) {
    return Listing
      .all()
  },
};
  • Router

This file contains two routes:

  • app.get, which is rendering the index.ejs with the listings retrieved from the database,
  • app.post, which is saving the records to the database.
const listingsController = require('../controllers').listings;
var path = require('path');


module.exports = function(app) {

  app.get('/', function(req, res) {
     listingsController.list(req, res)
      .then(function(listings){ // 'then' is crucial for this note
         res.render('index', { x: listings })
       });
   });

  app.post('/', listingsController.create);

}

Explanation

In order to explain the code above I'll use the following diagram.

CREATE
+---------------------------------------------+
                                           |
+-------------+   HTTP     +--------------+   |
|             |            |              |   |
| BROWSER     |  +------>  | ROUTER       |   |
|             |            |              |   |
+-------------+            +------+-------+   |
                               |           |
+----------------------+          |           |
                    |          v           |
<-----------------+    |   +------+-------+   |
 LIST          |    |   |              |   |
               |    |   | CONTROLLER   |   |
               |    |   |              |   |
               |    |   +------+-------+   |
               |    |          |           |
               |    |          |           |
               |    |          v           |
               |    |   +------+--------+  |
               |    |   |               |  |
               |    |   |   MODEL       |  |
               |    |   |               |  |
               |    |   +-------+-------+  |
               |    |           |          |
               |    |           | SQL      |
               |    |           v          |
               |    |                      |
               |    |         +---+        |
               |    |         |   |        |
               |    |         |   |        |
               |    |         |DB |        |
               |    +------>  |   |  <-----+
               |              |   |
               +-----------+  +---+


CREATE

As you can see (hopefully), the create method goes one way - we want to store a new record in a database and that's it. We don't want to get anything back. Let's analyse it step by step:

  1. On a homepage there is a following form:
<form class="form" action="/" method="post">
  <p2> Add a place: </p2>
  <input type="text" name="listingname" placeholder="listingname" class="single_form_window">
  <input type="text" name="listinglocation" placeholder="location" class="single_form_window">
  <input type="text" name="listingprice" placeholder="price" class="single_form_window">
  <input type="text" name="listingdescription" placeholder='description' class="single_form_window description">
  <input type="submit" value="submit">
</form>

It sends us to / with a post method.

  1. router, seeing this, calls a listingsController.create function:
// in router
app.post('/', listingsController.create);
  1. This function picks the data from the form and create a new record in the database:
// in a controller
const Listing = require('../models').Listing;

module.exports = {
  create(req, res) {
    return Listing
      .create({
        name: req.body['listingname'],
        location: req.body['listinglocation'],
        description: req.body['listingdescription'],
        price: req.body['listingprice']
      })
  }
  1. And that's it. We don' want anything back, just want to see our record in the database.

*5) Side note - read after completing the whole note: create method also returns a promise object, but I'm ignoring it in my program as in my create function I just want to save the record in the database and don't want to get anything back. *

LIST

The read element of CRUD (list method) is more complicated.

  1. We want a user to be able to see the records on the website right at the start. That's why at the app.get('/') we want to get all of the listings.

  2. For this purpose I'm using the listingsController.list(req, res) functions that will get the data from the database and pass it to the index page.

// in router
app.get('/', function(req, res) {
   listingsController.list(req, res)
    .then(function(listings){
       res.render('index', { x: listings })
     });
 });
  1. The list function is pretty straightforward
// in a controller
list(req, res) {
  return Listing
    .all()
},
  1. What's interesting, this method is not returning all our records, but only a promise object. This promise object will become the data only when we trigger it.

  2. For this purpose we use .then.

  3. Let's analyze the following piece code step by step. I'm chaining the methods now for educational purposes:

listingsController.list(req, res).then(function(listings){
    res.render('index', { x: listings })
  });
  • we call the list method which returns us the promise object,
  • and right after that we activate the data by calling .then.
  • at the end we render the index page and pass the data to later use them on the index page.

WHY!?

JS operates in the browser. As users usually do/want may operations at the same time, JS needs to be prepared for this. In order to explain it we can use the following analogy.

JS is a wedding planner and wants everything to be ready at the right time. Because of this, before a wedding cake enters the ballroom, it sends a person to buy this cake and wait for a right moment to enter.

The cake will enter a room only when asked by the wedding planner. So think of .this as of a call from the wedding planner to that helping person.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment