82

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.

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
Nabeel Khan
  • 3,715
  • 2
  • 24
  • 37
  • 12
    Voted to reopen, as synchronous requests do have valid use cases. (E.g. `chrome.webRequest.onBeforeRequest.addListener` won’t let you do asynchronous operations, leaving you no choice.) – Константин Ван Jan 21 '22 at 02:54

6 Answers6

23

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.

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().

RiZKiT
  • 2,107
  • 28
  • 23
  • 2
    I can't believe that there's no way to do it. There's a legit case in which it only makes sense to make a sync xhr. In the `beforeunload` event handler. And this means that in the project I am workin on right now, I'll have to _mock_ axios because they used it. And use `XMLHttpRequest` instead. Funny isn't it? – Iharob Al Asimi Mar 08 '23 at 20:40
  • @IharobAlAsimi I can only guess for what purpose you want to make an AJAX call in the onbeforeunload handler, but I've added option 4, so maybe that fits your problem. – RiZKiT Mar 09 '23 at 22:15
  • I start a payment flow, and I want to ensure it is cancelled even if the user closes the tab. Not an easy thing unfortunately. – Iharob Al Asimi Mar 12 '23 at 11:58
0

If you don't want to use the fetch api you will have to use callbacks, event listeners, XMLHttpRequest.

  • 2
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 09 '22 at 03:37
-1

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", true);
   xhttp.send();
Jorge Olivares
  • 1,477
  • 1
  • 11
  • 14
-3

You simply need to add callback function as parameter.

function fetchOHLC(yUrl, callback){
    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;
        
            callback({t,o,h,l,c});
    
    })
    .catch(function(error) {
        console.log(error);
        callback(null, error);
    });    
}

fetchOHLC(yUrl, function(response, error){
    if (response == null) {
        console.log(error);
    } else {
        var fetchData = response;
        alert(fetchData);
    }
});
Niu Bee
  • 53
  • 4
-3

This is how I have implemented and it's working perfectly fine. The real hero here is the JS fetch API.

var url = "http://excample.com/get/bytes"
var audio;
audio = $('audio');

fetch(url, {
    method: 'GET',
    headers: {
        'Authorization': 'Bearer ABCDEFGHIJKLMNO'
    }
}).then(response => {
    response.blob()
        .then(blob => {
            const objectUrl = URL.createObjectURL(blob);
            audio[0].src = objectUrl;
        }).catch(e => {
            console.error(e);
        })
}).catch(error => {
    console.error(error);
});
Munam Yousuf
  • 431
  • 1
  • 6
  • 17
-10

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.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • why are we using return twice in it? – Nabeel Khan Jun 24 '17 at 11:07
  • oh ok, sorry i missed that the return in closure returns to fetch only not fetchOHLC – Nabeel Khan Jun 24 '17 at 11:08
  • 1
    @NabeelKhan no it returns into the promise chain. So it resolves the promise returned by then with that. thats why ive returned that promise, so you can get the fullfilled data... – Jonas Wilms Jun 24 '17 at 11:11
  • 45
    This provides sound advice that the question might be misguided, but doesn't answer the question. – 5fec Jan 05 '21 at 02:22
  • 9
    I am not an expert, but what about (initial) values that are absolutely needed from the api without which the whole rest of the javascript does not make any sense? – johannes_lalala Feb 21 '21 at 13:23
  • @johannes have a look at "top level await". Also much better to show some progress bar / loading spinner than to just block the browser somehow. – Jonas Wilms Feb 21 '21 at 14:48
  • Top level await only works in modules. Sometimes you need to load in your configuration settings before you go into modules (or you are not using modules). – Vaccano Mar 04 '21 at 07:15
  • 21
    I know I am commenting on a four years old question, but in some rare cases, making a synchronous web request makes sense and is legitimate in my opinion. For example, I am making a synchronous web request to download OAuth settings required by my API (client_id and authority) stored in a static file (e.g. settings.json). The file can also be heavily cached using cache-control. MDN Web Docs explain how to do that: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#example_http_synchronous_request – Roberto Prevato Apr 03 '21 at 18:01
  • 45
    Yeah this is a terrible answer, it's a shame that the stack overflow community is full of so many people who think like you. The question is "how to make a synchronous fetch request in javascript" which your answer does not answer, instead you chose to answer condescendingly about how a normal fetch could be done. – Matthew Ludwig May 04 '21 at 18:37
  • 2
    @matthew well if you really want _that_ answer: Use [a synchronous XmlHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#synchronous_request). It is deprecated in all browsers though. You're welcome. – Jonas Wilms May 04 '21 at 18:55
  • 4
    @JonasWilms `XMLHttpRequest` may be deprecated, but still there are some strictly synchronous Browser APIs in your Browser. Today. Like WebRequest, the only valid way to secure a Browser (intercepting SSL is invalid). And if you do not want to re-invent the wheel using JavaScript every time (aka bloat the Browser) you need strictly fully synchronous web requests at that level. **Async, await, Promises or other Callbacks cannot be used here. In all current Browsers.** (Chrome tries to stop to support WebRequest with Manifest v3. Looks like Mozilla is a bit more clever in that respect ..) – Tino Jul 05 '21 at 18:08
  • 2
    @johannes_lalala Instead of `init(); main();` call `init().then(() => main())` and use `async function init() { ..; await fetch(URL); .. }`. However this only works in top level. [But not in callbacks of webRequest/onBeforeRequest](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/onBeforeRequest) which must return something strictly synchronously, so you cannot wait for something asynchronous in such callbacks. – Tino Jul 05 '21 at 18:25
  • I have issues with submit in an Angular PWA and its event not being handled using async await Promise. I am using old school XmlHttpRequest and it works. Sync could be a working option in some cases. Maybe I am erroring in some other way though.. just wanted to give an example of async not working in some cases. – Tore Aurstad Sep 26 '21 at 23:31
  • 2
    **I do know `fetch` does not need to be synchronous**, but Chrome extensions’ `chrome.webRequest.onBeforeRequest.addListener` won’t let me do asynchronous operations. We’re here because we have our own good reasons. – Константин Ван Jan 21 '22 at 02:51
  • 1
    Well, thats a temporary limitation "From Firefox 52 onwards, instead of returning BlockingResponse, the listener can return a Promise which is resolved with a BlockingResponse" ... – Jonas Wilms Jan 21 '22 at 09:41
  • 1
    IMO, another reasonable example is where the end user is me. I'd rather wait a couple TCs for my page to render than write more code to enhance my own experience. – DaveL17 Sep 20 '22 at 01:42
  • @RobertoPrevato I need to do exactly what you are doing. It seems silly to have to string up promises etc. when just having an sync method would solve the problem very simply. – Nick.Mc May 16 '23 at 09:47