DEV Community

Cover image for Error Handling in JavaScript (Golang Style)

Error Handling in JavaScript (Golang Style)

Bibek on June 18, 2021

In this short article, we are going to see how we can handle error in JavaScript in Golang style. I am assuming, you have some experience with Jav...
Collapse
 
drumstickz64 profile image
Drumstickz64 • Edited

You can actually turn this into a utility function, like so:

async function goCatch(promise) {
    try {
        const result = await promise
        return [result, null]
    } catch (err) {
        return [null, err]
    }
}
Enter fullscreen mode Exit fullscreen mode

You could also use an object like Brendan said.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

I would wrap it in a higher order function though, something that takes an async function and returns a new async function with the added catch logic

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️ • Edited

Something like this, I guess:

const safe = fn => (*args) => fn(*args)
   .then(res => [res, null])
   .catch(err => [null, err])
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bibekkakati profile image
Bibek

Yeah. That can be way of implementing it.

Collapse
 
bibekkakati profile image
Bibek • Edited

Yeah. Utility function can be very helpful.

Collapse
 
douglascalora profile image
DouglasCalora • Edited
import { Loading, Notify } from 'quasar'

/**
 * @param {Promise} promise
 * @param {object} config={notifySuccess, notifyError, useLoading}
 * @example promiseHandle(new Promise(), { notifyError: { message: 'Erro' }, notifySuccess: { message: 'Sucesso' } })
 */
export default async function (promise, config = {}) {
  const {
    notifySuccess = {},
    notifyError = {},
    useLoading = false,
    onLoading
  } = config

  onLoading && onLoading(true)
  useLoading && Loading.show()

  const primiseToBeExec = typeof promise === 'function' ? promise() : promise
  const hasNotify = notify => Object.keys(notify).length

  try {
    const data = await (Array.isArray(promise) ? Promise.all(promise) : primiseToBeExec)
    hasNotify(notifySuccess) && Notify.create({ type: 'success', ...notifySuccess })
    return { data, error: null }
  } catch (error) {
    hasNotify(notifyError) && Notify.create({ type: 'error', ...notifyError })
    return { data: null, error }
  } finally {
    onLoading && onLoading(false)
    Loading.hide()
  }
}
Enter fullscreen mode Exit fullscreen mode

I added a callback onLoading so I can do somenthing while function is running.

const { data, error } = await promiseHandler(callbackFn, { onLoading: value => console.log('is loading?', value) })

Collapse
 
bibekkakati profile image
Bibek

👨🏼‍💻

Collapse
 
jsnanigans profile image
Brendan Mullins

Nice, but I would personally use an object instead of the array as a return type

Collapse
 
bibekkakati profile image
Bibek

I prefer array because if we use object, destructuring will be an issue if there is more than one block in same level. Also we need to be aware of the property name.

Collapse
 
jankapunkt profile image
Jan Küster

Property name can be set by convention across your whole project. Let's say { error, result } which is to me most verbose and would not lead to accidental access compared to array indices

Thread Thread
 
bibekkakati profile image
Bibek

Yeah, that is right. But in case of multiple blocks in the same scope it can create issue, as you will not be able de-structure it like this

const {error, result} = await method();

// second method call will create an issue
const {error, result} = await method2();
Enter fullscreen mode Exit fullscreen mode

But in case of array, you can use other variable name in the second method call.

Feel free to correct me, if I am missing something.

Thread Thread
 
jsnanigans profile image
Brendan Mullins

a few ways you could avoid this:

const responseOne = await methodOne();
if (responseOne.error) return

const responseTwo = await methodTwo();
if (responseTwo.error) return

// of if you want destructuring
const {error: methodOneError, result: resultOne} = await methodOne();
if (methodOneError) return
const {error: methodTwoError, result: restultTwo} = await methodTwo();
if (methodTwoError) return
Enter fullscreen mode Exit fullscreen mode

Im not saying the array descructuring is worse, its just a prefference

Thread Thread
 
erikhofer profile image
Erik Hofer

You can rename the variable when destructuring an object.

const {error, result} = await method();

const {error: error2, result: result2} = await method2();
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
bibekkakati profile image
Bibek

@jsnanigans Yeah, It's just a preference.

Thread Thread
 
bibekkakati profile image
Bibek • Edited

@erikhofer I am aware of that.

Collapse
 
grzegorzbielski profile image
Grzegorz Bielski

I'm not a huge fan of this pattern.
The idea of explicitly returning errors rather than throwing unchecked errors is great, but the proposed implementation is flawed - we need to always check the elements of the tuple before using the value to see if there is an error which will become error-prone rather quickly.
Fortunately, this is an already solved problem, known in other langues as Either or Result type, in which all of these ifs are abstracted away in form of map and flatMap / chain operations.
Potential implementation: gigobyte.github.io/purify/adts/Eit...

Collapse
 
bibekkakati profile image
Bibek

Got your point. After all it's all about own preference.

Collapse
 
baenencalin profile image
Calin Baenen

Better yet, just use GoLang.

Collapse
 
bibekkakati profile image
Bibek

Good idea. 😉

Collapse
 
baenencalin profile image
Calin Baenen • Edited

Of course it is! Everyone knows Go is the best language objectively.

Collapse
 
chinmaykb profile image
Chinmay Kabi

I saw this in a Fireship video, ditto 👀

Collapse
 
bibekkakati profile image
Bibek

Is it? Need to check it.

I saw this in a 3 years old article.

Collapse
 
njavilas2015 profile image
njavilas2015 • Edited

in typescript

async function goCatch<T>(promise: Promise<T>): Promise<[T | null, null | Error]> {
    try {

        const result: Awaited<T> = await promise

        return [result, null]

    } catch (err) { return [null, err] }
}


const main = async (params: params) => {


    const [store, err] = await goCatch(qbpbspfzfeyudz.create(params.store))

}

Enter fullscreen mode Exit fullscreen mode
Collapse
 
outthislife profile image
Talasan Nicholson

Can just do if (error) though.

Collapse
 
bibekkakati profile image
Bibek

Yeah, we can do that. Sometimes I just like to check explicitly.

Collapse
 
clsource profile image
Camilo

Nice idea. Thanks for sharing :)

Collapse
 
bibekkakati profile image
Bibek

I'm glad that you liked it. 😊

Collapse
 
bibekkakati profile image
Bibek

Got it. Thank you for sharing that.

Collapse
 
bibekkakati profile image
Bibek

Sure :)