Polling Until Getting Specific Result?
Solution 1:
Here's an more extensible solution based on the post polling with async/await
Just add the following utility methods:
const poll = async function (fn, fnCondition, ms) {
let result = await fn();
while (fnCondition(result)) {
await wait(ms);
result = await fn();
}
return result;
};
const wait = function (ms = 1000) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
};
Then you can call it like this:
let fetchReport = () => axios.get(reportUrl);
let validate = result => !result.data.summary;
let response = await poll(fetchReport, validate, 3000);
Solution 2:
Recent versions of Node.js, have support for async / await.
Below is an example of using it..
One major advantage of async / await, it's very easy to follow the code, and understand it's logic. If for example you wanted to extend this, to have a max try's feature, it would be trivial to do. (hint) It's just a for loop :)
let count = 0;
var client = {
get: function () {
return new Promise(function (resolve, reject) {
count ++;
setTimeout(function () {
if (count > 4) resolve({status:'DONE',otherStuff:'Other Stuff'});
else resolve({status: `count: ${count}`});
}, 1000);
});
}
}
async function someFunction() {
while (true) {
let dataResult = await client.get('/status');
console.log(dataResult.status);
if (dataResult.status == "DONE") {
return dataResult;
}
}
}
(async () => { let r = await someFunction(); console.log(r); })();
Solution 3:
Here's an example of a function that uses promises and polls until you get the desired result. I've also parameterized it so that you can pass in the polling interval and a timeout value:
// create a promise that resolves after a short delay
function delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
// interval is how often to poll
// timeout is how long to poll waiting for a result (0 means try forever)
// url is the URL to request
function pollUntilDone(url, interval, timeout) {
let start = Date.now();
function run() {
return client.get(url).then(function(dataResult) {
if (dataResult.status === "DONE") {
// we know we're done here, return from here whatever you
// want the final resolved value of the promise to be
return dataResult;
} else {
if (timeout !== 0 && Date.now() - start > timeout) {
throw new Error("timeout error on pollUntilDone");
} else {
// run again with a short delay
return delay(interval).then(run);
}
}
});
}
return run();
}
// sample usage
// polls every 500ms for up to 30 seconds
pollUntilDone(someUrl, 500, 30 * 1000).then(function(result) {
// have final result here
}).catch(function(err) {
// handle error here
});
The key here is to chain your promises so each time you call run()
again, you return its value so it is chained to the prior promise. Then, whenever you finally return a value or throw an exception, the original promise will get that value or error as the resolved value or rejected reason.
Note that I added a timeout because you really never want to be polling forever, particularly in cases where some unforeseen and recurring error might not reject the promise, but won't get you the result you want.
Solution 4:
I just had to solve a similar problem. Below is a gist of my solution:
// api call with interval until receiving a specific data.
const callApi = () => {
return new Promise((resolve, reject) => {
console.log('calledAPI!');
setTimeout(()=>{
var myNumber = parseInt(Math.random()*10, 10);
resolve(myNumber);
}, 1000);
});
}
const callIntervalFunc = () => { // need to wrap it with a function because setInterval is not a function and cannot call it from outside otherwise.
const callInverval = setInterval(async()=>{
console.log('checking the api...');
var responseNumber = await callApi();
console.log('Got response! ',responseNumber);
if (responseNumber === 5) {
clearInterval(callInverval);
console.log('responseNumber is 5!! ends.');
}
}, 2000);
}
callIntervalFunc();
Solution 5:
Following continuousPromise
method will do the job, it requires 2 parameters:
Promise responsible for fetching data
delay (in ms) in subsequent calls
let exit = false; const continuousPromise = (promise, interval) => { const execute = () => promise().finally(waitAndExecute); const waitAndExecute = () => { if (exit) { return; } setTimeout(execute, interval) }; execute(); }
How to use
continuousPromise(() => {
return axios.get("something.json")
.then((res) => {
if (res && res.status !== 'PENDING') { // Check here for expected result
exit = true;
}
})
.catch((error) => {
exit = true;
console.log(error);
})
}, 1000);
Post a Comment for "Polling Until Getting Specific Result?"