A little lifehack for handling async/await requests in JavaScript

Anton Kosykh
2 min readJul 27, 2017

--

Before I start…

Hello readers (if someone reads it at all). Today I want to talk about async/await requests in JavaScript.

Earlier I was against async/await and considered it a bad replacement for Promises. Because async/await forces us to wrap async calls in try/catch statement. And this is really ugly.

But now I understood my mistake and realized how to use this feature correctly (in my opinion).

So, let’s go deeper

Many people use try/catch in every async/await call. But I propose a more beautiful solution. Just wrap it in function that will not reject, but return an object with success flag.

Here I wrote a simple function that I use for fetch queries:

async function query (url, options = {}) {
let response = null
try {
response = await fetch(url, options)
if (!response.ok) {
throw new Error('Failed to fetch')
}
return {
success: true,
response,
data: await response.json()
}
} catch (error) {
return {
success: false,
error,
response
}
}
}

Of course, in my code I use a more complex function that works with my API, but for example I decided to simplify that.

And here is an example of usage:

async function foo () {
let result = await query('/foo/bar')
if (result.success) {
console.log('Done', result.data)
// And here u have access to full response (result.response)
} else {
console.log('Fail', result.error)
// Here u also have full respones (result.response)
}
}

You’ll immediately ask me: “What is the advantage of this solution?”. The answer is simple. You can’t skip catch statement, but you can skip unnecessary part of condition. You also can remove unnecessary nesting with return

async function foo () {
let result = await query('/foo/bar')
if (!result.success) {
console.log('Fail', result.error)
return
}
console.log('Done', result.data)
}

And you can remove first nesting by wrapping it in a callback

function handleError (result) {
console.log('Fail', result.error)
}
async function foo () {
let result = await query('/foo/bar')
if (!result.success) return handleError(result)
console.log('Done', result.data)
}

And finally…

I am a big fan of functional programming and I wrote a one more function…

function asyncWrapper (callback) {
return async function (...args) {
try {
return {
success: true,
result: await callback(...args)
}
} catch (reason) {
return {
success: false,
reason
}
}
}
}

… that wraps callback in try/catch statement and returns result without reject:

let result = await asyncWrapper(fetch)('/foo/bar')
console.log(result) // { success: true, result: Body }

Thanks for reading. So, what do you think about this? Is it better than try/catch or not? Please write in comments

--

--

Anton Kosykh
Anton Kosykh

Written by Anton Kosykh

— Stricty pants nerd that sounds like total dork (according to one of the readers) — Also YOLO JavaScript Engineer

Responses (1)