Coding Journal

Jordan Vidrine

Daily Coding Journal

An experienced business owner + musician with a demonstrated history of management in the Energy sector and an insatiable appetite for learning new and complex skills. Transitioning from an ownership role & seeking employment in Web Development as a Jr Full Stack Developer.

July 2nd 2019

Promise Chaining

I’ve worked with basic promises with the past couple of exercises in the Node.js course. What if we wanted to to multiple tasks, after each step of operating with the Promise returned. Ie. First get a lat,long from a geocoding API, then use that data to get weather info; or mark a task as complete, then get the total number of incomplete tasks left to do.

Here is where Promise Chaining comes into play.


// Here is an example of a basic Promise that will always return the sum after 2 seconds. An error is
// not programmed to take place.
const add = (a, b) => {
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve(a+b)
    },2000)
  })
}

// What if you want to perform more asynchronous actions after receiving the resolved promise? One way
// (a bad way) is to nest more calls to the Promise inside of the returned resolution as such. This
// will QUICKLY get confusing and convoluted so it is not a good idea
add(1,2).then((sum) => {
  console.log(sum)

  add(sum,5).then((sum2) => {
    console.log(sum2)
  }).catch((e) => {
    console.log(e)
  })

}).catch((e) => {
  console.log(e)
})

// Promise Chaining
add(1,1).then((sum) => {
  console.log(sum)
  // return a call to add, this will send the returned value to the next chained .then() method
  return add(sum, 2)
}).then((sum2) => {
  console.log(sum2)
  // this one call to .catch() will apply to any error that happens in the chain
}).catch((e) => {
  console.log(e)
})

Working with mongoose promises

In the following example we look at how promise chaining can be used to perform different asynchronous operations. We first, update a users age, by finding it according to their ID. Then we print the number of users with that same age to the console.

require('../src/db/mongoose')
const User = require('../src/models/user')
const _id = '5d1ab0b280912d4560f77785'

// for updates, mongoose takes care of the $set operator, no need to add it
User.findByIdAndUpdate(_id,{age: 55}).then((user) => {
  console.log(user)
  return User.countDocuments({age: 55})
}).then((countedUsers) => {
  console.log(countedUsers)
}).catch((e) => {
  console.log(e)
})

Async/Await

This is something I learned about a couple months ago when I was first getting into programming. I did not know what I was doing, but now that I have come back to it, it is such a useful tool.

Adding async in front of a new function will cause the function to return a promise. The promise is fulfilled with the value you choose to return from the function. The await operator can only be used inside of async functions.

let doWork = () => {}
console.log(doWork()) // undefined

let doWork2 = async () => {}
console.log(doWork2()) // Promise { undefined }

Revisit promise chaining with Async Await

The big advantage of using this language is that it helps code syntactically LOOK synchronous while performing asynchronous tasks. The code below is doing the same as the previous Promise Chaining example, but it read a lot better. This is better than promise chaining because it also gives you access to multiple results in the same scope of the async function, rather than only one result per call.

const add = (a, b) => {
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      resolve(a+b)
    },2000)
  })
}

const doWork = async () => {
  const sum = await add(1,99)
  const sum2 = await add(sum, 50)
  const sum3 = await add(sum2, 3)
  return sum3
}

doWork().then((info) => {
  console.log('Result:', info)
}).catch((e) => {
  console.log(e)
})
What happens if a promise is rejected and not resolved?

As soon as a promise is rejected in an async function, it jumps to the .catch() call instead of running coder that comes after it.

const add = (a, b) => {
  return new Promise((resolve,reject) => {
    setTimeout(() => {
      if (a < 0 || b < 0) {
        return reject('Numbers must be non-negative')
      }
      resolve(a+b)
    },2000)
  })
}

const doWork = async () => {
    const sum = await add(1,-99) // will break here with 'Numbers must be non-negative'
    const sum2 = await add(sum, 50)
    const sum3 = await add(sum2, 3)
    return sum3
}

doWork().then((info) => {
  console.log('Result:', info)
}).catch((e) => {
  console.log(e)
})

Refactoring with async/await

The following is a cleaner version of the code a couple notches above that deleted a task by ID and returned the amount of incomplete tasks with promise chaining. Using async/await cleans it up nicely.

require('../src/db/mongoose')
const Task = require('../src/models/task')

const _id = '5d1a79b4fc29fa3af499212b'

const deleteTaskAndCount = async (id) => {
  const task = await Task.findByIdAndDelete(id)
  const count = await Task.countDocuments({completed: false})
  return count
}

deleteTaskAndCount(_id).then((count) => {
  console.log(count)
}).catch((e) => {
  console.log(e)
})

Here is a little example of an app.post() and an app.get() method being cleaned up with async/await. I find this much more visually pleasing as well as easier to understand the specifics of what is going on.

// add user
app.post('/users', async (req,res) => {
  const user = new User(req.body)

  try {
    await user.save();
    res.status(201).send(user)
  } catch (e) {
    res.status(400).send(e)
  }
});

// find all users
app.get('/users', async (req,res) => {
  try {
    const users = await User.find({})
    res.send(users)
  } catch (e) {
    res.status(500).send(e)
  }
})

Convert Object Keys to array

Learned this today. I am surprised this passed over my head in the past months of learning. Object.keys({}) will convert the object passed to it, into an array of its keys.

Object.keys({name: 'Jordan',age: 32})
//  ['name', 'age']
Setting up express routers to consolidate code per resource

It is important to use the express router when code starts to build up. It is also good to use a router for each resource you are interacting with, saving any confusion. Here is the basic structure:

const router = new express.Router()

router.get('/test', (req,res) => {
    res.send('This is from my other router')
})

module.exports = router

// in index.js
const userRouter = require('./routers/user')
app.use(userRouter)

With all this, today I completed the section on REST APIs and using Express to perform CRUD operations on the MongoDB database with mongoose. Next up will be to add authentication.

I finished the last two hours of the day implementing my own version of what I worked through today. I setup a static handlebars page with an input to save data to a mongo database. I then used a button to generate a random entry from the data base and show it on the screen. Very simple, but I think it solidified some things I needed within Express and using the Fetch api.

Back to blog...