0

I would like to involve more logic than just return new Promise(...); from a function. I'm not sure if storing a Promise into a variable is changing the "synchronicity" behind it, as every example I've seen does not do that. I would also like to store a Promise into a variable in general to return at the end, even when I'm not involving conditionals, as it just seems bad for debugging and in general to have all the logic reside in a return statement.

function doSomething(){
    var promise_var1;

    if (condition){
        //Do something async, like an AJAX call to an API
        setTimeout(function(){promise_var1 = Promise.resolve('a')}, 3000);
    }else{
        //Do something synchronous, like setting a default value
        promise_var1 = Promise.resolve('b');
    }    

    return promise_var1;
}

doSomething().then(function(value){console.log('c'+value)});

I'm currently getting

doSomething() is undefined

however I've tried various ways so I may be misunderstanding something conceptually.

Edit: "Duplicate" question is asking how to handle conditionals inside a promise. I'm asking how to return promises via variable (to achieve single exit). That may not be possible because JavaScript is weakly typed and Promise variable return vs. Promise return may behave differently, but if there is a solution to do that I would prefer single-exit over multiple returns.

BLaZuRE
  • 2,356
  • 2
  • 26
  • 43
  • 2
    if `condition` is true, your function will return `undefined` because you aren't creating the promise until 3 seconds later. but by then, your function returned 3 seconds earlier. –  Feb 02 '18 at 01:42
  • Why make it complicated? `let doSomething = condition => condition ? somethingAsync() : Promise.resolve('b');` function always returns a Promise you can `.then` whether it resolves in one turn of the event loop or 3 minutes. – Jared Smith Feb 02 '18 at 01:46
  • Possible duplicate of [How to handle the if-else in promise then?](https://stackoverflow.com/questions/33257412/how-to-handle-the-if-else-in-promise-then) – Daniel B Feb 02 '18 at 10:07
  • @JaredSmith I'm trying to do a single return rather than having the branching logic return at different places. – BLaZuRE Feb 02 '18 at 16:33
  • @BLaZuRE You get a Promise of 'b', or a Promise of whatever the async thing is, but you always get a Promise. If that's not what you want, then please edit your question because that looks like what you were trying to do in your code. If you want to branch on a condition, then you have to branch on a condition, whether you do it inside the promise or out. Inside would look like `let doSomething = condition => new Promise(resolve => if (condition) { resolve(someAsyncThing); } else { resolve('b'); });` but I would struggle to call that 'better'. – Jared Smith Feb 02 '18 at 16:48
  • I've updated my answer. – Jared Smith Feb 02 '18 at 16:57
  • @JaredSmith I also stated I wanted to store it into a variable. The purpose of storing it into a variable was to have a single return to hopefully make it easier to follow. Of course the logic would be a lot more complicated than what I've posted as it's focused on the core code in question, so putting it all in a single ternary operator loses its value. For simple conditionals, sure. To me having 2+ exit paths seems bad in more complicated code. – BLaZuRE Feb 02 '18 at 18:48
  • @BLaZuRE you're either going to have multiple call sites for `resolve`, or multiple `return` statements. Pick your poison. Check my updated answer, but there's no way to square a circle. – Jared Smith Feb 02 '18 at 19:18
  • @JaredSmith True, but now I know I'm dealing with a circle. Documentation isn't clear on that a Promise object behaves differently than from storing the same Promise into a variable and how that would fit in with stack frames. – BLaZuRE Feb 02 '18 at 22:33

3 Answers3

1

Try writing your promise like this.

   function doSomething(condition){

        var promise_var1= new Promise(function(resolve, reject) {
            if(condition){
               //resolve after your async action
               setTimeout(resolve('a'), 3000);
            }else{   
              //resolve immediately
              resolve('b');
            }
        });


        return promise_var1;
    }
Gratus D.
  • 787
  • 7
  • 22
1

To answer your question simply: Yes. You can absolutely store a promise in a variable. This is exactly why we have promises. It allows us to "store" a value that may not exist yet, so we can easily pass it around to other parts of the program.

Ultimately you still need to call a callback to get at the internal value, either with .then or with the overly-sweet sugar of async/await. But until you are ready to define your callback, you can pass that future-value around just like any other value.

However, in your example, I don't think the use of a temporary variable does anything to improve the logic or readability of your code. (And in fact, it doesn't work at all, because your if doesn't add a promise to the returned variable until 3 seconds later, after .then has already been called.) Just make sure that every branch of your conditional returns a promise, and you're good to go.

function doSomething(condition){
    if (condition){
        //Do something async, like an AJAX call to an API
        return new Promise(resolve => {
          setTimeout(() => resolve('a'), 3000);
        })
    }
    //Don't actually need an else because if condition returns.
    //Do something synchronous, like setting a default value.
    return Promise.resolve('b');
}

doSomething(true)
  .then(value => console.log('c ' + value));
doSomething(false)
  .then(value => console.log('c ' + value));
skylize
  • 1,401
  • 1
  • 9
  • 21
  • I wanted to have a single return hence a variable that would take a promise in 2+ different places. I imagined that would be easier for future people to trace back through the code rather than searching for returns and exits. – BLaZuRE Feb 02 '18 at 16:40
  • I guess that might be a matter of preference and style. To me, as long as all returns are of equivalent type (in this case the type being a promise) there is no benefit to comprehension in moving all returns to the end. In fact, you can often use an `if`-gate strategy, where the first line or few lines is checking to be sure there is any reason to run the rest of the function, and then the rest is all flat because the default or do-nothing branches are already out of the way. – skylize Feb 03 '18 at 00:37
0

Why make it complicated?

let doSomething = condition => condition ? somethingAsync() : Promise.resolve('b'); 

function always returns a Promise you can .then whether it resolves in one turn of the event loop or 3 minutes

Update

here's a version with one return and the branch inside the Promise

let doSomething = condition => {
  return new Promise(resolve => {
    if (condition) {
      resolve(someAsyncThing());
    } else {
      resolve('b');
    }
  });
};

I would still argue that it's less readable and simple than the version above, but it's your codebase, YMMV.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83