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.

Tiugo image

Modular, Fast, and Built for Developers

CKEditor 5 gives you full control over your editing experience. A modular architecture means you get high performance, fewer re-renders and a setup that scales with your needs.

Start now

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

Neon image

Next.js applications: Set up a Neon project in seconds

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

Get started →

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay