refetching datas on user action – Vanilla JS

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