3

I recently started writing promise code in coffeescript/javascript and I love it. The one thing that I don't understand is how to handle flow control with promises. Consider the following code with Q.

outerFunction = ->
  Q()
    .then ->
      doSomethingAsync
    .then (result) ->
      return result if result is someSpecialValue 
      #do I really have to continue this chain or nest my promises in a new promise chain?
      ...
    .then ->
      ...
    .then ->
      ...

I want to return to the caller early. Is this even possible?

I don't want to use magic exceptions for flow control. Do I need to do something like this or is there a better way?

...
.then (result) ->
  return result if result is someSpecialValue
  return Q()
    .then -> 
      ...
    .then -> 
      ...
CharlesTWall3
  • 548
  • 4
  • 12
  • 2
    It isn't possible to return to the caller. – Loïc Faure-Lacroix Jan 30 '16 at 04:51
  • IIRC, usually when you attach a `then` you're returning the original promise, so those are all going to fire simultaneously when the original promise returns. They're not going sequentially. – Andrew Jan 30 '16 at 04:51
  • @Andrew how does parallelization work when the value is being transformed in each promise? I'm – orourkedd Jan 30 '16 at 05:01
  • Thinking about fetch where response.json() is returned and then the next promise I'm the chain gets the json formatted response as its parameter – orourkedd Jan 30 '16 at 05:02
  • @Andrew there is no parallelization in promises. They are done simply asynchrously. It's not like multi threading. It's just usefull to organize async IO flows. Where you don't have to wait for an IO to process other IO. Keep in mind that JS works in a single thread. so no parallelization at all. – Loïc Faure-Lacroix Jan 30 '16 at 05:15
  • You want the Maybe monad https://curiosity-driven.org/monads-in-javascript#p18 – Jared Smith Jan 30 '16 at 19:12

1 Answers1

4

Here's a more complete answer, returning to the caller isn't possible. Because Promise are running asynchrously... in other words, the caller already returned when the promise started working. So returning to the caller isn't possible because the caller is already gone.

If you want to leave the promise, you can simply call this.reject() You can reject with a parameter. It will get caught in a catch promise. You can reject from a catch clause too if you don't want it to process any more then. Then at some point, this will result in the promise failing.

It might not do exactly what you want because you'll have to handle at least on final catch to handle the errors or why you left early from the promise. But even the catch is a promise.

outerFunction = ->
  Q()
    .then ->
      doSomethingAsync
    .then (result) ->

      if error
         this.reject(result)

      return result if result is someSpecialValue 

    .then ->
      ...
    .then ->
      ...
    .catch (error) ->
      console.log("Handling error", error)

Here's a bit more documentation on promises: http://promisejs.org/ This is a good read.

I hope you understand that using reject is pretty much like trying to early exit from a function couple of stacked function by raising an exception. I do not encourage this as it could be quite terrible and hard to understand the logic behind it. If you have to early exit from a promise even though there is no exceptions or error, then you probably have to rethink about your flow.

What you could do is this instead:

outerFunction = ->
  Q()
    .then ->
      doSomethingAsync
    .then (result) ->

      if return_now
         return result if result is someSpecialValue
      return Q()
         .then ->
           ...
         .then ->
           ...
         .then ->
           ...

You could return your result or return a promise that will continue the process chain.

Loïc Faure-Lacroix
  • 13,220
  • 6
  • 67
  • 99