DEV Community

Lori "Lei" Boyd
Lori "Lei" Boyd

Posted on

8 2

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.

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

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

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →