Skip to content

Instantly share code, notes, and snippets.

@gnapse

gnapse/index.md

Last active Jul 8, 2020
Embed
What would you like to do?
Promise vs async/await

then(onSuccess).catch(onFailure)

This one catches errors not only during the ajax request, but during the onSuccess handler execution.

const response = ajax(options).then(onSuccess).catch(onFailure)

The appropriate translation to async/await could be something like this:

try {
  const response = await ajax(options)
  onSuccess(response)
} catch(error) {
  onFailure(error)
}

Simple and fair enough. So far so good.

then(onSuccess, onFailure)

However, we usually do not want to catch errors occurring inside the onSuccess handler. This can lead to errors difficult to catch or even test for.

Imagine you have a bug inside your onSuccess handler. Something that throws an error under a certain condition. If your onFailure handler catches it too, in addition to catching legitimate errors during the ajax request, you may end up with "failed" network requests that did not actually fail.

That's why the original promise callback handler .then supports receiving two callbacks.

const response = ajax(options).then(onSuccess, onFailure)

Translating this one is, in my opinion, not doable in async/await clearly.

let response = undefined

try {
  response = await ajax(options)
} catch(error) {
  onFailure(error)
}

if (response !== undefined) {
  onSuccess(response)
}

Am I missing something here? Can the above be written more clearly? I admit that my promise-accustomed brain may be slipping though.

@resynth1943

This comment has been minimized.

Copy link

@resynth1943 resynth1943 commented Jun 14, 2019

What if, when you use .then, the function throws an Error (using the throw operator)? This is, of course, mitigated by making ajax an async function.

@gnapse

This comment has been minimized.

Copy link
Owner Author

@gnapse gnapse commented Jun 14, 2019

@resynth1943 if you mean that in processing the results we knowingly want to throw an error (say the network request was ok, but its content indicates that the operation failed) then I would do this:

function catchResponseErrorCode(json) {
  if (json.error_code != null) {
    throw new Error(json.error_code); //intentional error case
  }
  return json; // success case
}

ajax(options)
  .then(catchErrorResponseCode)
  .then(onSuccess, onError) // <- your actual success and error handlers

If you wanted to do this with async/await, and still achieve that your onError handler does not end up catching unwanted errors occurring inside onSuccess (i.e. bugs in the onSuccess code) can you tell me how you'd handle this not using .then and using async/await?

@jostschmithals

This comment has been minimized.

Copy link

@jostschmithals jostschmithals commented Jul 3, 2020

Interesting question!

I'd say that errors which occur in onSuccess should be caught directly in this function (if you really don't want to handle those errors, leave the catch block empty):

try {
  const response = await ajax(options); 
  onSuccess(response);
} catch(error) {
  onFailure(error);
}

const onSuccess = response => {
  try { 
    // ...
  } catch(err) {}
}

This leads to an equivalent solution with a nested try/catch:

try {
  const response = await ajax(options);
  try {      
    onSuccess(response);
  } catch(err) {}
} catch(error) {
  onFailure(error);
} 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.