简体   繁体   中英

Recursion with Asynchronous Functions and Bluebird Promises in JavaScript

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" ( ie 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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM