0

In JavaScript, I have four sets of functions:

Set_A
  synchronousFunction_One
  synchronousFunction_Two
  synchronousFunction_Three
  synchronousFunction_Four
  synchronousFunction_Five

Set_B
   objectA.asynchronousFunction_One
   objectA.asynchronousFunction_Two
                       .
                       .
                       .
   objectA.asynchronousFunction_N

Set_C
   objectA.asynchronousFunction_Three
   objectA.asynchronousFunction_Four
                       .
                       .
                       .
   objectA.asynchronousFunction_M

Set_D
  synchronousFunction_Six

I need each set to be run one after another, in a particular order and with certain constraints:

  1. None of the functions in Set_A can be called until an externally provided promise resolves
  2. The synchronous functions in Set_A are iterated over, called once each
  3. After each call to a function in Set_A, the iterator pauses and waits for Step 4 and Step 5, below, to resolve before moving onto the next element in Set_A
  4. Set_B is iterated over and each method is called once, opening several asynchronous connections to the internet
  5. Once all of the calls in Step 4 have resolved, Set_C is iterated over and each method is called once, again opening several asynchronous connections to the internet
  6. Once all calls in Step 5 have resolved, the iterator in Step 1, above, moves on to the next element in Set_A

So, essentially what we are doing here is waiting for some external promise to resolve, then we call a function to "prime the pump", so to speak. Then, we iterate over part of an object's interface, the "independent part"--methods that can be called whenever one likes. Then, we iterate over another part of that object's interface, "the dependent part" ( i.e. none of the methods in the dependent part will close properly unless all of the methods in the independent part have closed at least once ). And then finally, we call the cleanup function. Once that is done, we start over with the next element in Set_A and prime the pump again.

The highest level of abstraction, again using the Bluebird Promise Library, looks like this:

function doAllTheThings( externalPromise ) {

  var Set_A, Set_B, Set_C; // Array<Function>

  return new Promise( promiseToDoAllTheThings );
  function promiseToDoAllTheThings( resolve, reject ) {

    externalPromise.then( go );

    function go() {

      var primePump = Set_A.pop();
      if ( !primePump ) return;

      primePump();
      callEverythingInSet_B()
        .then( callEverythingInSet_C )
        .then( cleanUp )
      ;
    }

    function callEverythingInSet_B() {

      var promises = [];
      for ( var index in Set_B )
        promises.push( Set_B[index]() );
      return Promise.all( promises );
    }

    function callEverythingInSet_C() {

      var promises = [];
      for ( var index in Set_C )
        promises.push( Set_C[index]() );
      return Promise.all( promises );
    }

    function cleanUp() {

      // Do stuff
      go();
    }
  }
}

I'm having a really hard time with this; I spent several hours yesterday factoring and refactoring, every time not getting the behavior I expected. I'm still working on my actual code; so maybe I'll find the odd semicolon that's driving me crazy or something like that.

But in the meantime, I thought I'd post this here and ask--am I understanding the Bluebird Promise Library correctly? Given the code above, should one expect the behavior I've described? If not--can you provide some demo code that will?

My follicles thank you.

1 Answers1

0

Yes, that seems to work. However, some tips:

  • don't put your call of the go() function in cleanUp. Chain it right after the .then(cleanUp) in your go function itself, making the recursive nature obvious (and keeping the references local).
  • That

    return new Promise( promiseToDoAllTheThings );
    function promiseToDoAllTheThings( resolve, reject ) {
    

    is wrong. The returned promise is never resolved or rejected, you don't use those callbacks. However, you even shouldn't use them here at all. Just omit that promiseToDoAllTheThings, and only do a

     return externalPromise.then( go );
    

    directly.

  • Instead of those plain for loops, try to use Array::map, it'll look better :-)
  • you may use Promise.each instead of your go loop
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Bergi for the win! Thank you, man. Are you connected to Bluebird? I see you all over the place, man. ( I'm typing all this up in a Code Pen now; will link for posterity once it's ready. ) –  Feb 05 '15 at 21:50
  • Also--do you happen to know which performs better, vanilla `for` or `Array::map`? This is server-side code, so I'm trying to stick with what's smokin' fast. ( Thus, the choice of Bluebird. ) –  Feb 05 '15 at 21:52
  • No, @BenjaminGruenbaum and @ Esailija are the bluebird authors, I haven't contributed to it yet but am only working on my own (academical) promises implementation. – Bergi Feb 05 '15 at 21:53
  • 1
    [for-loops are a bit faster as they don't have to call functions](http://stackoverflow.com/q/6551139/1048572). However, this is a micro-optimisation, aim for clean code. The network connections are what limits the performance of your method. – Bergi Feb 05 '15 at 21:56
  • @LMiz: Your [suggested edit](http://stackoverflow.com/review/suggested-edits/6961846) would have better been a comment – Bergi Feb 05 '15 at 22:38
  • Don't you think the link would be kind of buried? –  Feb 05 '15 at 22:39
  • Nah. I'd even upvote it, then the comment is shown not collapsed. If you want to make it really visible, better edit your question, – Bergi Feb 05 '15 at 22:40
  • Given the three, I'd go for leaving it in a comment here. I'll add it on it's own, next. –  Feb 05 '15 at 22:44
  • 1
    Here's a CodePen mock up of the major revisions @Bergi suggests: [http://codepen.io/anon/pen/WbXwVv](http://codepen.io/anon/pen/WbXwVv) Works beautifully! Thanks, man! –  Feb 05 '15 at 22:46
  • @Bergi not sure where else to find you - wanted to ask if you were aware at #promises and to invite you to lurk some. We have interesting discussions there from time to time and your feedback would be appreciated on things :) – Benjamin Gruenbaum Feb 06 '15 at 11:03