ES6 (or Javascript) : how to loop on the same promise

In the era of the promises, who likes to wait for an uncertain amount of time ?

A promise is the key to hope.
No need to setTimeout(function(){}, XXXXX) milliseconds. You don’t know if you waited too much, and even worse… : you don’t know if you did not wait enough.

Actually, you can tell your program to wait for a promise, then check a condition, then chain a new promise if the condition is not met. The only subtle delta to achieve this is to trigger the condition testing and the return value inside functions ; here is an example :


aPromise.then((pollResponse) => {
const promiseWhile = (condition, oldResponse, promiseGenerator) => {
if (!condition(oldResponse)) {
return typeof oldResponse === 'function' ? oldResponse : () => oldResponse
}
return promiseGenerator().then((newResponse) => promiseWhile(condition, newResponse, promiseGenerator))
}

const promiseGenerator = (execute, oldResponse) => {
return promiseWhile((newResponse) => newResponse.code === 'PENDING', oldResponse,
() => execute().then((newResponse) => promiseGenerator(execute, newResponse)))
}

return promiseGenerator(() => query(`/myApi/pollStatus`), pollResponse)
})
.then((pollResponse) => {
const result = pollResponse()
console.log(result.code) //'COMPLETE'
})

Given a method called query, which returns either {code: ‘PENDING’} or {code: ‘COMPLETE’}, This code runs the query method regularly and stops when the value of code is no more ‘PENDING’. But this does not wait for an arbitrary amount of time.

If the condition is not true anymore, it returns a function whose result is the value to fetch.
Else it chains the previously resolved promise with a promise calling query again and checking the same condition again.

That is all.

There is also a lighter version without value return, and where ‘query’ is immediate (actually, it occurs within condition()), but unfortunately you have to define a small interval to avoid saturation on your event loop :


const waitWhile = (condition, resolve) => {
if (!condition()) {
resolve()
}
setTimeout(() => waitWhile(condition, resolve), 1)
}

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*