1

I am trying to figure out if it's possible to use promises instead of a standard callback in a recursive function.

The way I have it now:

function recursive(data, cb){

     (function promiseProvider(data){

          return newThenable(data).then(function(val){
                 if(val.a){
                    cb(null, val);
                 }
                 else {
                    return promiseProvider(val);
                 }

          });

     })(data);

}

This works, but I can't figure out how I could make a pure promise implementation.

Perhaps this would work?

  function recursive(data){

      return newThenable(data).then(function(val){
               if(val.a){
                  return // <<< ???
                 }
                 else {
                   return recursive(val);
                 }

        });

     }

However, that doesn't work.

halfer
  • 19,824
  • 17
  • 99
  • 186
Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • What happens if something goes wrong and `.a` is never set? – Walf Nov 11 '16 at 09:39
  • 1
    _"return // <<< ???"_, _" LOL no that doesn't work..."_ Yes, that pattern should return expected result. After first call to `recursive`, return value from `recursive` is a `Promise`, as `.then()` returns a new `Promise` object. – guest271314 Nov 11 '16 at 09:44

3 Answers3

5

Given you were calling the callback with val as the result argument, just

return val;

from the then callback. That's it.

function recursive(data){
     return newThenable(data).then(function(val){
         if (val.a){
             return val;
         } else {
             return recursive(val);
         }
     });
 }
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • That approach would only return last `val` to `.then()` chained to `recursive` – guest271314 Nov 11 '16 at 10:30
  • @guest271314 Which is exactly what the OP is looking for? – Bergi Nov 11 '16 at 11:56
  • Could be. The only reason to `return val` is if `val` object is not defined outside of scope of function calls. Interpreted Question as how to return accumulated results derived at each call. The accumulated results could be occurring presently at object `val`. If that is case and `val` is referencing an object inside of calls, yes, return `val` object. If object is originally defined outside scope of calls, and passed to `recursive` to begin process, it is not necessary to return `val`. OP could use `return` pattern at Question, then reference the object at chained `.then()` – guest271314 Nov 11 '16 at 16:04
  • 1
    @guest271314 There's nothing about accumulation in the question, so I'd rather not assume that. – Bergi Nov 11 '16 at 18:22
3

Push val to an array. If val.a return array of results, else call recursive with val and array of accumulates results as parameter. See multiple, sequential fetch() Promise

  function recursive(data, results) {
    return newThenable(data).then(function(val) {
      if (val.a) {
        // results.push(val);
        return results
      } else {
        results.push(val);
        return recursive(val, results).catch(function(e) {console.log(e)});
      }
    });
  }
Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177
  • Where did you get that array from? The non-promise code didn't use one either. – Bergi Nov 11 '16 at 10:26
  • 1
    You shouldn't have that `.catch(function(e) {console.log(e)})` *inside* the function. It's the caller's obligation to catch errors. – Bergi Nov 11 '16 at 10:28
  • @Bergi The array can be passed when `recursive` is called, or not passed at all, having been created before call to `recursive` – guest271314 Nov 11 '16 at 10:29
  • @Bergi There should not be an issue with `.catch()` inside function. Multiple `.catch()` functions can be used. Placed `.catch()` within function to illustrate that option; though could be removed without affecting pattern or result. – guest271314 Nov 11 '16 at 10:32
  • 1
    @guest271314 Ah, I had not considered where the empty array comes from, but that might be a problem as well, yeah. However, my comment was about the OP never using any arrays anywhere, not even in the callback-style code, so I wondered why you'd introduce that `results` array. – Bergi Nov 11 '16 at 12:31
2

Nowadays the ES8 async/await makes it more readable. I skipped the try-catch for now.

async function recursive(data, results = []) {
    let val = await newThenable(data);
    if (val.a) {
        return results
    } else {
        results.push(val);
        return recursive(val, results);
    }
}
Niels Steenbeek
  • 4,692
  • 2
  • 41
  • 50