0

In the following program, when recurse(prog) is initially called (line 64), it recursively digs into the expressions exp described in prog (line 1), switching between the case where exp.type = A, B or C.

At the bottom most level of the recursive call (when case("C")), I am calling verySlowMan(exp.value) that looks up a list of collections to check whether a collection with the name of exp.value exists or not.

If yes, the collection is returned

If no, a new Erroris return

The problem is that verySlowMan() take his time to retrieve a collection.

For simplicity, I made a simple if else condition, but verySlowMan will ultimately make an XHR request. So it is unpredictably slow

The question is the following :

How to propagate the return value of verySlowMan all the way up the recursive call to get a nice list of collections as a result of calling recurse(prog) ?

Currently, for understandable reasons, I get [ null, [ null, null ], null ]. But I have really no clue about how to solve it.

I tried to return a deferred.promises from verySlowMan, but in this case I think recurse() should also return a new promise for each recursive call.

(1) I'm not sure about how to make this properly

(2) I doubt it's the best way

NB : The amount of items in prog, collections and the cases in recurse() can potentially become very long.

Here is the program :

var prog = {
  type : "A", value : [
    { type : "B", value : "C1" },
    { type : "B", value : [
      { type : "C", value : "C2" },
      { type : "C", value : "end" }
    ]},
    { type : "B", value : "C3" }
  ]
}

var collections = [
  { name : "C1", data : ["item1", "item2", "item3"]},
  { name : "C2", data : ["item1", "item2", "item3"]}
]

function verySlowMan( collectionToFind ){

  collections.forEach(function(collection){

    if ( collection.name === collectionToFind ) {
      return collection;
    }else{
      return new Error("No Collection");
    }
  });

  return null;
}

function recurse(exp){

  switch(exp.type){
    case("A"):
      var As = [];
      exp.value.forEach( function(B){
        As.push ( recurse(B) );
      } );
      return As;
      break;

    case("B"):
      var Bs = [];
      if (typeof(exp.value) === 'string') {
        return verySlowMan( exp.value );

      } else {
        exp.value.forEach( function(C){
          Bs.push ( recurse(C) );
        } );
        return Bs;
      }
      break;

    case("C"):
      return verySlowMan( exp.value );
      break;

    default:
      throw new Error('wrong type');
  }
}

console.log( recurse(prog) ); // -> [ null, [ null, null ], null ]
4
  • what expected output for your sample? seems like always should throw new Error Commented May 29, 2015 at 21:15
  • also when you so return inside forEach callback - it not return from function where forEach run Commented May 29, 2015 at 21:19
  • you would have to use callbacks and the whole recursion function will return the result in callbacks, if this is ok for your use case Commented May 29, 2015 at 21:20
  • In your example verySlowMan is not asynchronous. That makes your code confusing. Also, do you want to work with normal callbacks or with promises? You need to write all loops and recursive function calls in an asynchronous style if those internally also call asynchronous code. Commented May 29, 2015 at 21:24

1 Answer 1

1

Here is an example with promises.

function verySlowMan( collectionToFind ) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      for(var i = 0; i < collections.length; i++) {
        if ( collections[i].name === collectionToFind ) {
          resolve(collections[i]);
          return;
        }
      }
      reject(new Error("No Collection"));
    }, 100);
  });
}

function recurse(exp){
  function errorHandler(err) {
    if(err.message === "No Collection") return null;
    else throw err;
  };
  switch(exp.type){
    case("A"):
      return Promise.all(exp.value.map(recurse));
    case("B"):
      if (typeof(exp.value) === 'string') {
        return verySlowMan(exp.value).catch(errorHandler);
      } else {
        return Promise.all(exp.value.map(recurse));
      }
    case("C"):
      return verySlowMan( exp.value ).catch(errorHandler);

    default:
      return Promise.reject(new Error('wrong type'));
  }
}

recurse(prog).then(function(result) {
  console.log(result);
}).catch(function(err) {
  console.log(err.stack);
});
Sign up to request clarification or add additional context in comments.

2 Comments

As I understand, you are using Promise from ES6. Could I do the same with Q ?
Ok, with Q it's pretty much the same. but instead of return new Promise(function(resolve, reject) I used return Q.Promise(function(resolve, reject) Thanks a lot for the help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.