Nabeel Khan
Nabeel Khan

Reputation: 3993

How to make javascript fetch synchronous?

I'm using fetch to get data json from an api. Works fine but I have to use it repeatedly for various calls, thus it needs to be synchronous or else I need some way to update the interface when the fetch completes for each component.

function fetchOHLC(yUrl){
    fetch(yUrl)
    .then(response => response.json())
    .then(function(response) {
                alert(JSON.stringify(response.query));

            var t = response.created;
            var o = response.open;
            var h = response.high;
            var l = response.low;
            var c = response.close;
        
        return {t,o,h,l,c};
    
    })
    .catch(function(error) {
        console.log(error);
    });    
}

var fetchData = fetchOHLC(yUrl);
alert(fetchData); // empty ?

Is there any other way to achieve it other than using fetch? (I don't want to use jquery preferrably).

Thanks

Edit

The question is about fetch-api, not ajax, not jquery, so please stop marking it as duplicate of those questions without reading it properly.

Upvotes: 103

Views: 179345

Answers (6)

franksands
franksands

Reputation: 2053

I had to make a syncronous JS fetch for my particular scenario. This is the code that worked for me:

const request = new XMLHttpRequest();
request.open("GET", "/bar/foo.txt", false); // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {
  console.log(request.responseText);
  return request.responseText;
}
return null;

Upvotes: 11

Jorge Olivares
Jorge Olivares

Reputation: 1492

You always can use the old fashion way using xhr. Here a example of a request.

   var xhttp = new XMLHttpRequest();
   xhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        document.getElementById("demo").innerHTML = this.responseText;
       }
     };

   xhttp.open("POST", "cookies.php", false);
   xhttp.send();

Upvotes: -3

Stefan Genov
Stefan Genov

Reputation: 21

I had the exact same problem - I was calling fetch from a method on beforeunload and it sometimes triggered, sometimes didn't.

I found this article: https://web.dev/articles/disallow-synchronous-xhr

So I removed the async/await from the event handler and added keepalive: true to the fetch options. Seems to be working consistently.

Before:

save: async function () {
    const requestOptions = {
        method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(data),
    };
    const response = await fetch(url, requestOptions);
}

window.addEventListener("beforeunload", async function (event) {
    await self.save();
});

After:

save: async function () {
    const requestOptions = {
        method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(data),
            keepalive: true,
    };
    const response = await fetch(url, requestOptions);
}

window.addEventListener("beforeunload", function (event) {
    self.save();
});

Upvotes: 2

Steely Wing
Steely Wing

Reputation: 17597

You can use await, but await only can be used in async function, so you need to wrap your top-level code in async function

function fetchJSON(url) {
    return fetch(url)
        .then(response => response.json())
        .catch((error) => {
            console.log(error);
        });
}

(async () => {
    var json = await fetchJSON('https://api.github.com/users/steelywing/repos');
    alert(json);
})();

But if you can use .then(), better use fetchJSON().then()

fetchJSON('https://api.github.com/users/steelywing/repos')
.then((data) => {
    alert(data);
});

Upvotes: 3

RiZKiT
RiZKiT

Reputation: 2511

fetch is intended to do asynchronous calls only, but there are some options:

Option 1

If XMLHttpRequest is also fine, then you can use async: false, which will do a synchronous call.

But there is a deprecation warning in the whatwg specs since 2014 and some browsers are already complaining in the development tools. It can therefore be assumed that sooner or later it will no longer work.

Option 2

Use async/await which is asynchronous under the hood, but feels like it is synchronous, see https://stackoverflow.com/a/54950884/2590616

Option 3

or else I need some way to update the interface when the fetch completes for each component

This sound like fetch + Promise.all() would be a good fit, see https://stackoverflow.com/a/52013616/2590616

Option 4

If you want to send analysis data or session data when leaving a page (e.g. in onbeforeunload) and want to be sure that the data is sent to the server, which is not guaranteed with a normal asynchronous AJAX call, you can use the Beacon API with Navigator.sendBeacon().

Upvotes: 31

Jonas Wilms
Jonas Wilms

Reputation: 138267

If you came here because you dropped "how to make javascript fetch synchronous" into a search engine:

That doesn't make much sense. Performing network operations is not something which requires CPU work, thus blocking it during a fetch(...) makes little sense. Instead, properly work with asynchrony as shown in the duplicate linked above.


In case you really need a synchronous request (you don't), use the deprecated XMLHttpRequest synchronous variant, to quote MDN:

Note: Starting with Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), Blink 39.0, and Edge 13, synchronous requests on the main thread have been deprecated due to their negative impact on the user experience.

const request = new XMLHttpRequest();
request.open('GET', '/bar/foo.txt', false);  // `false` makes the request synchronous
request.send(null);

You can find more information on MDN.

Upvotes: -15

Related Questions