Promises And SetTimeout
Solution 1:
The idea is in the right direction. You just need to resolve the current promise also when you have called the function recursively, otherwise your current promise will never fulfil.
Note however, that you create a stack of promises if the wait is long.
function promiseTest(counter = 1000) {
return new Promise( (resolve, reject) => {
if ( waitValue ) {
console.log('waitValue is now true');
resolve('FIRST PROMISE');
} else if ( counter <= 0 ) { // dont wait forever.
reject('waited too long');
} else {
console.log('Count down: ' + counter);
setTimeout( _ => { // make sure to call `resolve` after the nested promise resolved:
promiseTest(counter-1).then(resolve);
}, 3000);
}
})
.then( result => {
return `SECOND PROMISE: the result is: ${result}`;
});
}
var waitValue = false;
promiseTest().then ( result => {
console.log('done:', result);
});
// schedule the change of the waitValue:
setTimeout(_ => waitValue = true, 4000);
Note how the output will have some traces of each of the nested chained promises that resolved.
Alternative
I find it more intuitive to perform the recursive call on a function you define within the Promise
constructor callback, not on the function that creates the Promise
. That way you only create one promise, and you avoid the promise constructor anti-pattern which is present in your idea (and the above working version of it):
function promiseTest(counter = 1000) {
return new Promise( (resolve, reject) => {
(function loop(counter) {
if ( waitValue ) {
console.log('waitValue is now true');
resolve('FIRST PROMISE');
} else if ( counter <= 0 ) { // dont wait forever.
reject('waited too long');
} else {
console.log('Count down: ' + counter);
setTimeout( loop.bind(null, counter-1), 3000);
}
})(counter); // initial value of count-down
})
.then( result => {
return `SECOND PROMISE: the result is: ${result}`;
});
}
var waitValue = false;
promiseTest().then ( result => {
console.log('done:', result);
});
// schedule the change of the waitValue:
setTimeout(_ => waitValue = true, 4000);
Note how the output is slightly different from the first version, which reflects that there is only one new
promise involved
NB: it is not essential, but I prefer counting down from some value (1000), and to pass it as an argument to the anonymous function that does the looping.
Solution 2:
setTimeout( promiseTest, 3000);
will not work, this might call the promiseTest
function again but never resolve the promise created in the outermost invocation.
Instead of messing around with callbacks that much, promisify the asynchronous primitive that you are using, setTimeout
:
function wait(t) {
return new Promise(resolve => {
setTimeout(resolve, t);
});
}
and then use that in your polling function:
function promiseTest(counter = 1000) {
if (waitValue) {
console.log('waitValue is now true');
return Promise.resolve('FIRST PROMISE');
} else if (counter <= 0) { // dont wait forever.
return Promise.reject(new Error('waited too long'));
} else {
console.log('WAIT MESSAGE: ' + counter );
return wait(3000).then(() => {
return promiseTest(counter-1);
});
}
}
Post a Comment for "Promises And SetTimeout"