3

Assume we have a simple front end and (let's assume Angular if it matters) and a back end app. Say the front end app does a get request. Usually the angular repository makes an $http.get request which returns a promise (angular 1) or an observable that can be converted to a promise (angular 2 or 4), and then the repository returns that promise. Then the angular service will look something like

repository.makeTheGetCall().then(function (response) {
  // process response
}); 

This is fine usually.

1) But what if all the logic on the service is dependent on this 1 call? Then we've essentially nested the entirety of the service within a .then clause.

2) Or what if based on the response of the first Get request, we make another request. And based on that response, we make another request, and so on. Then we will have a bunch of then clauses chained.

Neither situations seems that rare, and both result in what appears to be 'ugly' code. Is there any other practice that can be used so to allow asynchronous calls but without having to return promises from the repository layer to the service layer?

Thank you :)

junvar
  • 11,151
  • 2
  • 30
  • 46
  • 3
    You don't have do put all of your code inside one function. You can create other functions which are called from inside your `.then` callback function. #2 doesn't sound like a problem to me. Promises are designed to be chained. (It's the alternative which is ugly: nested callbacks) – 4castle Oct 26 '17 at 22:36
  • 1
    "*Then we've essentially nested the entirety of the service within a .then clause.*" - yes, because logically that's what you want: the service runs only after the request. You don't have to syntactically nest the whole code there of course. – Bergi Oct 26 '17 at 22:43
  • 1
    "*Then we will have a bunch of then clauses chained.*" - yes, that's the [whole point of promises](https://stackoverflow.com/a/22562045/1048572) (and observables): they're monadic, so that you can *chain* them instead of having to nest them. – Bergi Oct 26 '17 at 22:44
  • 1
    If you don't like the "uglyness" of `then` calls, have a look at `async`/`await` syntax. – Bergi Oct 26 '17 at 22:45

1 Answers1

14

You can use async/await. It's the only alternative to classical .then() promise handling.

So, instead of doing this:

someServiceMethod() {
  repository.makeTheGetCall().then(function (response) {
    // process response
  }); 
}

You can do this:

async someServiceMethod() {
  const response = await repository.makeTheGetCall()
  // process response
}

The coolest thing is that we don't have any starting point for "callback hell", code is now flat (#1 in your list)

Also, if one of the Promises was rejected, we can handle the error in try/catch block. The good thing about it that we can have one place to catch all errors. (#2 in your list):

async someServiceMethod() {
  try {  
    const response = await repository.makeTheGetCall()
    const data = await repository.getDataForResponse(response)
    // process data or make another async call
  } catch (err) {
    // process error
  }
}

Good explanation of how to use it

vanelizarov
  • 1,064
  • 1
  • 8
  • 24
  • 2
    "*It's also a good practice to wrap lines of code that contain await in try/catch block*" - Nope. Just as it's not a good practice to put `.catch()` on every function call that returns a promise. You should only use `catch` (either one) when you *want* to handle an error, and just let it bubble to your caller otherwise. – Bergi Oct 26 '17 at 23:02
  • Bear in mind that errors in asynchronous callbacks can not be intercepted and handled externally by try and catch, as explained here: https://frontnet.eu/javascript-async-await-introduction-to-asynchronous-javascript-programming/ – Lucio Mollinedo Oct 20 '19 at 16:12