Reputation: 3993
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
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
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
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
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
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
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