11

Is it possible to make a native JavaScript while loop where the condition is a promise?

Edit: What I'm trying to do is implement a check before uploading a file to firebase storage, to see if a file with the same name already exists in the firebase storage. If there is already a file with the same name then add a random suffix and check again.

var storageRef = firebase.storage().ref().child(fileName);

while(storageRef.getDownloadURL()) {
    // create random number in between 0 and 100
    var random = Math.floor((Math.random() * 100) + 1);    
    storageRef = firebase.storage().ref().child(fileName + random);
}

storageRef.put(file);
sjbuysse
  • 3,872
  • 7
  • 25
  • 37
  • 1
    you probably want some sort of recursive function. Include your code to demonstrate your exact problem/requirement – musefan May 04 '17 at 10:22
  • Can you explain what you are trying to do. Technically you can make a loop with a promise being the condition but loop will exit immediately because until promise returns it will be false. Not that you can't invert it but explain what do you need? – Dellirium May 04 '17 at 10:22
  • 1
    A promise is not an observable. It will be resolved or rejected at some time. It does not provide a stream of values. – andreim May 04 '17 at 10:24

2 Answers2

19

Is it possible to make a native JavaScript while loop where the condition is a promise?

No, it is not.

There are a couple problems with trying to do that:

  1. With ES6 standard promises, there is no way to directly test the value of a promise. The only access to the eventually resolved value is with .then(). You can't do while (p !== resolved).

  2. Even if you could loop on the promises value, because Javascript is event driven and single threaded, if you did do a loop, then the asynchronous operation of the promise could never run and the promise could never get resolved anyway.

Instead, you simply use:

p.then(function(result) {
    // process result here
}).catch(function(err) {
    // process error here
});

If there's more you wanted to do in your loop, you would have to disclose that actual code before we could advise further on how to best do that.


If you want to repeat some operation until some condition, then just put that operation in a function, test the condition in the .then() handler and if you want to repeat, then just call the function again.

function doSomething() {
    // some async operation that returns a promise
}

function next() {
    return doSomething.then(function(result) {
        if (result < someValue) {
             // run the operation again
             return next();
        } else {
             return result;
        }
    });
}

next().then(function(result) {
      // process final result here
}).catch(function(err) {
    // process error here
});

EDIT: With ES7, you can use async and await. It won't really be a while loop, but it will obviate the need for a while loop because you don't have to "poll" the asynchronous value at all.

async function f() {
   let value = await somePromise;
   // put code here to execute after the promise
   console.log(value);
}

The internal execution of function f() will be paused until the promise resolves or rejects. Note that the caller of f() will not be paused. f() will return a promise immediately as soon as the await line is executed. That promise itself will resolve and reject when the internal execution of f() finally finishes.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • how could this be implemented with a set-timeout between so there is a delay between retries? – Scott Mar 11 '20 at 18:20
  • @Scott - See how the delay/retry works [here](https://stackoverflow.com/questions/57792389/native-js-promise-retry-wrapper/57793057#57793057) and [here](https://stackoverflow.com/questions/49522955/js-handle-multiple-sequential-failed-async-requests/49523085#49523085). – jfriend00 Mar 13 '20 at 02:43
  • It seems in your example that the next().then will execute immediately after the first time through, regardless of if next() is called recursively or returned. – mixophrygian Oct 21 '20 at 03:43
1

Yes it is!

What you're looking for are generators: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators.

I prefer using Observables e.g. RxJS for more complex stuff.

Rafal Pastuszak
  • 3,100
  • 2
  • 29
  • 31