DEV Community

Lori "Lei" Boyd
Lori "Lei" Boyd

Posted on

Fetching With Async/Await

I was going through a refactoring phase in my last project and decided to tidy up my fetch requests. I have multiple functions that not only look similar, but they all are about 49 lines long.

handleClick = () => {
    // fetches arrivalTimes
    fetch(`https://subway-times-api.herokuapp.com/stops/${this.props.stop.id}`)
    .then(r => r.json())
    .then(data => {
      // fetch here
      fetch(`https://subway-times-api.herokuapp.com/lines/${data.lines[0].id}`)
      .then(r => r.json())
      .then((line) => {
        // diggs through feed to find the arrays with the arrival times
        let feed = line.feed.filter( obj => Object.keys(obj).includes("trip_update"))
        let includesStopTimeUpdate = feed.filter(obj => Object.keys(obj.trip_update).includes("stop_time_update"))
        let stopTimeUpdateArrays = includesStopTimeUpdate.map(obj => obj.trip_update.stop_time_update)
        let stopTimeArrays = stopTimeUpdateArrays.map(obj => obj.map(obj2 => obj2))

        let trainObjs = []

        // adds the objects with train arrival times and stop ids to "state"
        stopTimeArrays.map(obj => obj.map(obj2 => trainObjs.push(obj2)))

        let arrivalTimes = trainObjs.filter(obj => obj.stop_id.includes(this.props.stop.stop_id + this.props.direction.direction))
        let trainArrivalObjs = arrivalTimes.map(obj => {
          let trainTime = new Date( parseInt(obj.arrival.time) *1000);
          let timeNow = new Date()

          // setting hours and mins
          let trainHour = trainTime.getHours() > 12? trainTime.getHours() - 12 : trainTime.getHours()
          let trainMin = trainTime.getMinutes()
          let currentHour = timeNow.getHours() > 12? timeNow.getHours() - 12 : timeNow.getHours()
          let currentMin = timeNow.getMinutes()

          // if trainHour is > current hour add 60 mins to trainMin
          if (trainHour > currentHour) {
            trainMin += 60
          }

          // take hour and min of train time and subtract each from the current time, if result is negative return 0
          return trainMin - currentMin
        })

        // if train is due or has past remove
        const arrivals = trainArrivalObjs.filter(time => time >= 0)

        this.setState({
          renderStopInfo: !this.state.renderStopInfo,
          arrivals: arrivals
        })
      })
    })
  }

This function throws away the whole DRY rule, and it's time to fix that. I've decided to throw all the logic here into my backend, so when I fetch for a stop, I get back all uptown and downtown arrival times converted to hours and minutes. To further refactor, I've decided to use async and await to handle my fetch.

Async

Async is a keyword before a function, and when called, the function returns a promise.

async function hello() {
    return "Hello, World!"
}
console.log(hello()) => Promise {<resolved>: "Hello, World!"}

Await

The MDN docs state "This [await function] can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value. In the meantime, other code that may be waiting for a chance to execute gets to do so."

So instead of writing my event handlers like so:

fetch(API)
.then(response => responce.json())
.then(data => this.setState({apiObject: data})

I can write the same thing with async/await

async function fetchFromApi(api) {
  let response = await fetch(api)
  let apiObject = response.json()
  return apiobject
}

fetchFromApi(API).then((apiObject)) => { 
  this.setState({
    apiObject: responseObject 
  })
})

In my opinion, the later is a lot easier to read. Also, because It's reusable, I can just call on fetchFromApi with any URL.

Top comments (3)

Collapse
 
taylorbeeston profile image
Taylor Beeston

Great post Lori!
I've found that for doing routine fetch calls like this, its even easier to do

const data = await (await fetch(url)).json();

This way you don't add unnecessary variables or add to the call stack, but still keep your fetch call down to one line.

Collapse
 
loripb profile image
Lori "Lei" Boyd

Nice! Thanks for the tip, Taylor!

Collapse
 
thisdotmedia_staff profile image
This Dot Media

Nice! Thanks for sharing Lori