I have the following code that I use for fetching data from multiple sources:
// Utility function that gets JSON with appropriate HTTP check function fetchJSON(...args) { return fetch(...args) .then(response => { if (!response.ok) { throw new Error(`HTTP error ${response.status}`); } return response.json(); }); } // Utility functon for repeated JSON requests that you can cancel when needed function startRepeatJSONRequest({url, options = undefined, callback, signal, interval = null}) { function doRequest() { fetchJSON(url, {...options, signal}) .then(data => { if (!signal.aborted) { callback(data); } }) .catch(error => { // ...handle/report error... }) .finally(() => { if (!signal.aborted && interval !== null) { setTimeout(doRequest, interval); } }); } doRequest(); } // Repeated requests for API A const controllerA = new AbortController(); startRepeatJSONRequest({ url: "https://example.com/request/A", callback(data) { // ...use `data` here... }, signal: controllerA.signal, interval: 3000, // or whatever }); // Repeated requests for API B const controllerB = new AbortController(); startRepeatJSONRequest({ url: "https://example.com/request/A", callback(data) { // ...use `data` here... }, signal: controllerB.signal, interval: 5000, // or whatever });
This works perfectly for my use case where I have to fetch from different sources with different frequencies.
My problem starts when I try to update the fetched URLs. I use a variable in the first place to set part of the url so I can manipulate it later, like this:
var money = usd; url: 'https://api.coingecko.com/api/v3/coins/markets?vs_currency=' + money + '&order=market_cap_desc&per_page=10&page=1&sparkline=true',
everything works fine, I change the variable with a button, but when the settimeout allows the function to fetch the data again, it wont fetch from the updated new URL where I’ve set the currency from eg. usd to eur, but uses the URL that was originally set when the page loaded.
How do I make this work?
Answer
Lets take a look at this example:
var money = "usd"; startRepeatJSONRequest({ url: "https://example.com/request/" + money, callback(data) { // ...use `data` here... }, signal: controllerB.signal, interval: 5000, // or whatever }); money.value = "eur";
in this example, it will always fetch https://example.com/request/usd
and not https://example.com/request/eur
because url
is a primitive data type;
A solution could be passing it as a reference:
var url = { base: "https://example.com/request/", value: "usd" } startRepeatJSONRequest({ url: url, callback(data) { // ...use `data` here... }, signal: controllerB.signal, interval: 5000, // or whatever }); url.value = "eur"
you should also change your startRepeatJSONRequest
because url is an object, so it becomes
fetchJSON(url.base + url.value, {...options, signal})
working js fiddle here: https://jsfiddle.net/m0daxqv6/
here a nice tutorial Primitives vs References
Cheers, Kalik1