polling on a promise to have always fresh data - javascript

i'm trying to fetch an endpoint that return a json object to display the result in my app.
this json return a list of online users, so i need to refresh this data every X seconds/minutes.
i've writed this code:
function getJustBlabData(url) {
return new Promise(resolve => {
const getData = fetch(url);
resolve(getData)
})
}
getJustBlabData('https://justblab.com/baxf/widget.php?q=online_usr')
.then((res) => res.json()
.then((data) => {
this.justBlab = data
this.loading = false
console.log(this.justBlab)
})
)
ive tried with setInterval like:
function getJustBlabData(url) {
return new Promise(resolve => {
setInterval(() => {
const getData = fetch(url);
resolve(getData)
}, 1000)
})
}
but i'm doing something wrong, but what?

Firstly, use fetch directly, since your getJustBlabData function is essentially just return fetch(url) wrapped in a new Promise - but since fetch already returns a Promise, there is no need for that code at all
i.e.
function getJustBlabData(url) {
return new Promise(resolve => {
const getData = fetch(url);
resolve(getData)
})
}
getJustBlabData(url).then ....
is equivalent (but in a lot of ways worse for error handling) to
fetch(url).then ....
If you want to do something every X seconds, do the whole thing in the interval
Like this
setInterval(() => {
this.loading = true;
fetch('https://justblab.com/baxf/widget.php?q=online_usr')
.then((res) => res.json())
.then((data) => {
this.justBlab = data;
this.loading = false;
console.log(this.justBlab);
});
}, 1000);
Now, this.justBlab gets updated every second
Note: Also, I've flattened your .then pyramid into a .then chain
to address the situation where requests could take longer than a second
(() => {
const processBlab = () => {
this.loading = true;
fetch('https://justblab.com/baxf/widget.php?q=online_usr')
.then((res) => res.json())
.then((data) => {
this.justBlab = data;
this.loading = false;
console.log(this.justBlab);
setTimeout(() => processBlab(), 1000);
});
processBlab();
})();
Only reason I put that all in a IIFE is to preserve this - as there is no context in the question as to what this is

You can use a promise to create a "wait" function and the restart the process again (get a new set of data) once that completes.
Here I used a 5 second delay between each cycle.
Doing it this way, if the server takes 10 seconds to reply this will do a new request 5 seconds after that response and avoids piling up requests.
let delayMSTime = 5000;
let howMany = 1;
function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function getJustBlabData(url) {
return new Promise(resolve => {
const getData = fetch(url);
resolve(getData);
})
}
function GoGetEm(myDelay) {
getJustBlabData('https://justblab.com/baxf/widget.php?q=online_usr')
.then((res) => res.json())
.then((data) => {
this.justBlab = data;
this.loading = false;
console.log(this.justBlab);
}).then(() => {
console.log("sleeeping for the "+howMany+" time:" + myDelay);
sleep(myDelay).then(() => {
howMany++;
GoGetEm(myDelay);
console.clear();
});
});
}
GoGetEm(delayMSTime);

Related

Fetch, then and setTimeout

How can I do setTimeout in then block?
I set setTimeout there, but program just goes through and does not wait for anything.
const controller = new AbortController();
const { signal } = controller.signal;
return fetch(url, { signal })
.then((response) => {
if (response.status === 404) {
controller.abort();
setTimeout(() => controller.abort(), 5000);
}
return response;
})
.then((response) => {
console.log('in');
setTimeout(() => controller.abort(), 5000);
return response.text();
})
.catch(() => {
return Promise.reject(new Error('empty link'));
});
I tried to set settimeout in then block, in catch block, tried to use for it the function which would return promise. The logic seems simple, but somehow I don't understand something about how to connect then block and settimeout functionality.
The setTimeout() call doesn't block. If you want to "await" for x milliseconds, you can do the following:
const timeout = (ms) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
const doSomething = async () => {
await timeout(3000);
// after 3 seconds
}

Use a promise result from a fetch-api in an if statement of another function - JS

So I have this fetch-api
let test = () => fetch(usd_api).then(response => response.json())
.then(data => data.exchange_rates.dash_usd);
Console log
let console_test = () => {console.log(test())}
How can use this number [[PromiseResult]]: 134.445... in the following function where the number 150 is.
function main(){
fetch(txs_api).then(response => response.json()).then(function(data) {
var amount = data.txs[0].vout[1].value;
if(amount == 150){
// SUCCESS!
$('#modal').modal('hide');
console.log('requests stopped');
clearInterval(interval);
}
})
}
let test = () => fetch(usd_api)
.then(response => response.json())
.then(data => data.exchange_rates.dash_usd);
You want too keep using the same promise, if you want to log the result of your promise you need to wait for it to be completed:
// with .then()
test().then(console.log);
// or with await if you can:
console.log(await test());
I figured it out. Don't know if it's the best way to do it but it's working.
function main(){
fetch(usd_api).then(response => response.json()).then(function(data) {
var dash_price = data.exchange_rates.dash_usd;
fetch(txs_api).then(response => response.json()).then(function(data) {
var amount = data.txs[0].vout[1].value;
if(amount == dash_price){
// SUCCESS!
$('#modal').modal('hide');
console.log('requests stopped');
clearInterval(interval);
}
})
})
}
Do not return value.
Because it returns to below function
function(data) {
return data.exchange_rates.dash_usd
}
If you want to return your value to a variable you have to use Promise like below.
let test = new Promise((resolve, reject) => {
fetch(usd_api).then(response => response.json())
.then(function (data) {
resolve(data.exchange_rates.dash_usd)
});
})
async function demo(){
let console_test = await test
console.log(console_test )
}
demo()
Note : Do not forget to use async and await

Keep calling an API every 2.5 seconds and close the call once desired result is achieved

I have an API to call every 2.5 seconds. Initially, the data inside the response object is null as the database is still updating it through a transaction. But on the subsequent 3rd or 4th try, I get the data. I am writing a reusable function for the same, however I get undefined. My goal is to keep calling the API until I get the value in my path and close the connection. Please advice.
P.S: The below API URL doesnt have any delay, but my private API has.
const getData = (url, path) => {
const interval = setInterval(async () => {
const result = await axios.get(url);
if (_.has(result.data, path) && result.data[path]) {
return result[path]
}
}, 2500)
return clearInterval(interval)
}
getData('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion')
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
JS Fiddle URL
Please advice.
You
return clearInterval(interval); // undefined
If you want to return a Promise which will resolve when the data is available, you could do something like this:
const getData = (url, path) => {
return new Promise((resolve, reject) => {
const interval = setInterval(async() => {
const result = await axios.get(url);
if (_.has(result.data, path) && result.data[path]) {
clearInterval(interval); // Clear the interval
resolve(result.data[path]); // Resolve with the data
}
}, 2500);
});
}
getData('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion')
.then(data => {
console.log(data); // Your data is available here
});
// OR
(async () => {
const version = await getData('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion');
console.log(version);
})();
Its because javascript is asynchronous as above comment is already mentioned. You can use either callbacks or promise in javascript. Here is the code:
const getData = (url, path, cb) => {
const interval = setInterval(async () => {
const result = await axios.get(url);
if (_.has(result.data, path) && result.data[path]) {
clearInterval(interval); //We found it remove the interval
cb(result.data[path]);
}
}, 2500);
};
getData(
"https://api.oceandrivers.com/static/resources.json",
"swaggerVersion",
data => {
console.log("test",data);
}
);
Here is the fiddle: https://jsfiddle.net/7pc4hq6t/3/
You could create an asynchronous delay:
const delay = milliseconds => new Promise(resolve, setTimeout(resolve, milliseconds));
Then use like this:
const getDataAsync = async (url, path) => {
while (true) {
const result = await axios.get(url);
if (_.has(result.data, path) && result.data[path]) {
return result.data[path];
}
await delay(2500);
}
}
const data = await getDataAsync('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion');
This avoids the multiple layers of nested callbacks, and produces much more readable code.

How to start function after previous function finishes in React Native

I have a problem. I know I can use promises to fix this problem, but I do not understand how to use them in my case. I just want get id from a function in another file (let's call it callApi), and then use this id to call another function, callApi2. The problem is callApi2 runs before apiCall finishes.
ApiCariIdAktor = {
cariIdAktor: () => {
const apikey = APP_CONSTANT.api_key;
const url = `https://api.themoviedb.org/3/search/person?api_key=${apikey}&language=en-US&query=iko%20uwais&page=1&include_adult=false`;
let id = 0;
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
responseJson.results[0].id
})
.catch((error) => {
console.log(error)
})
return 10;
}
}
setID() {
this.state.id = ApiCariIdAktor.cariIdAktor();
}
async componentDidMount() {
this.setID();
await new Promise(resolve => {
setTimeout(resolve, 1000);
});
this.panggilApi2();
}

How do I call 3 requests async?

I have to do a functionality to test if 3 APIs are running.
Thus, the user will click on the Test APIs button and it will return the status of each API (status: 200, 500, 404 etc). If an API return an error, I should show the error stack.
Screen example:
API Status Detail
url1.com 200 -
url2.com 200 -
url3.com 500 internal server error
My question is, how can I call the 3 requests in parallel and return the async result, I mean how can I update the screen of API request status without having to wait for the result of all requests
I was basing on that How do I call three requests in order?, but it returns the result synchronously.
*******EDIT*****
Thats my current code
app.get('/testDependencies', function (req, res, next) {
let objTestsResul = {}
var urls = ['url1', 'url2', 'url3'];
let index = 0
while(urls.length > 0) {
let url = urls.shift();
objTestsResult[index++] = testURL(url)
}
res.send(objTestsResult)
});
This function is the same for each URL:
function testURL(URL){
fetch(URL, {
method: 'GET'
})
.then(res => {
res.json()
})
.then(json => {
console.log(json)
return json
})
.catch(error => {
return error
})
}
Promises (mdn) seem to be what you're looking for. They're essentially a more readable version of callbacks, which allow you to execute code when something else occurs rather than having to wait for that trigger to occur before resuming execution.
let endpoint1 = () => new Promise(resolve => setTimeout(() => resolve('200'), 1000));
let endpoint2 = () => new Promise(resolve => setTimeout(() => resolve('201'), 2000));
let endpoint3 = () => new Promise(resolve => setTimeout(() => resolve('500'), 1500));
document.getElementById('test').addEventListener('click', () => {
document.getElementById('status').textContent = 'test running...';
Promise.all([
endpoint1().then(a => document.getElementById('result1').textContent = a),
endpoint2().then(a => document.getElementById('result2').textContent = a),
endpoint3().then(a => document.getElementById('result3').textContent = a),
]).then(() => document.getElementById('status').textContent = 'test complete');
});
<button id="test">test</button>
<div>status: <span id="status">not running</span></div>
<div>endpoint 1: <span id="result1"></span></div>
<div>endpoint 2: <span id="result2"></span></div>
<div>endpoint 3: <span id="result3"></span></div>
This is actually pretty straightforward if you can use Bluebird:
const { Promise } = require('bluebird');
app.get('/testDependencies', function (req, res, next) {
Promise.map(['url1', 'url2', 'url3'], url => testURL(url)).then(results => {
res.send(results);
});
});
You'll just need to ensure your promise function actually returns a promise:
function testURL(URL) {
let start_time = new Date().getTime();
return fetch(URL, {
method: 'GET'
}).then(res => {
res.json()
}).then(json => {
console.log(json)
return json
}).catch(error => {
return error
})
}
Promises can't be dependency chained unless you explicitly return them from the function that's involved in chaining.
If you're able to use async and await, I'd also recommend doing that as well as that can vastly simplify otherwise complex code.
Express can't send multiple responses. You will have to finish all calls or use WebSockets to stream data.
function testURL(URL) {
return new Promise((resolve, reject) => {
if (URL === 'url2') {
reject(new Error('Internal Server Error'));
return;
}
resolve({ status: 200 });
});
}
const main = async () => {
const urls = ['url1', 'url2', 'url3'];
// return resolved and rejected Promises because if one fails in Promise.all
// the function will throw and we won't have any access to any resolved Promises.
const results = await Promise.all(urls
.map(url => testURL(url).then(response => response).catch(error => error)));
// every error have a stack property, Set the status to whatever you want
// based on the error and store the stack and the message
const objTestsResul = results.reduce((result, cur, i) => {
result[urls[i]] = cur.stack
? { status: 500, message: cur.message, stack: cur.stack }
: cur;
return result;
}, {});
console.log(objTestsResul);
};
main();

Categories

Resources