0

I have a couple of jQuery Ajax requests, which have to be synchronous, but they keep locking/freezing the browser, until the response is received. My main problem is, that until the response is received I have to display a spinning icon, but due to the freezing the spinner is not displayed and even if it miraculously is it doesn't animate.

This is the event displaying the spinner and sending the request:

$(document).on('click', '#open-button', function () {

    var input = "some text";
    var wrapper = $('#wrapperWindow');
    wrapper.children().animate({
        opacity: 0
    }, 500);
    wrapper.children().remove();
    wrapper.append('<div id="loading-spinner" style="display:none;"></div>');
    var spinner = $('#loading-spinner');
    spinner.css({
        backgroundImage: 'url("img/loading.gif")',
        opacity: 0
    });
    spinner.show();
    spinner.animate({
        opacity: 1
    }, 500);

    var dataForTab = requestData(input); //<-- the request

    if (dataForTab.length > 0) {
        //do stuff
    }

});

The request:

function requestData(input) {

    var result = null;

    $.ajax({
        async: false,
        type: "POST",
        url: "/some/url?input=" + input,
        dataType: "json",
        retryLimit: 3,

        success: function (json) {
            result = json;
        },

        error: function (xhr, err) {
            console.log(xhr);
            console.log(err);
        }
    });

    return result;
}

Until the request returns the received JSON data, everything stops moving. How can I fix this please?

Dropout
  • 13,653
  • 10
  • 56
  • 109
  • 6
    You can't .... the way to fix it is to use asynchronous processing – Arun P Johny Oct 22 '14 at 08:52
  • have a look at - http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call – Arun P Johny Oct 22 '14 at 08:53
  • 2
    [$.ajax().async](http://api.jquery.com/jQuery.ajax/) - *Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active* – Arun P Johny Oct 22 '14 at 08:54
  • 4
    "have to be synchronous" - why? This is almost certainly an XY problem. – Amadan Oct 22 '14 at 08:56
  • "Synchronous Ajax requests “lock” browser" is pretty much a definition of synchronous AJAX. Unless you can redesign your application to use async requests you cannot avoid it. – joews Oct 22 '14 at 08:56

2 Answers2

4

That's the essence of synchronous requests, they are locking. You may want to try to move the requests to a web worker. Here's an example (not using XHR, but it can give you an implementation idea)

A web worker is implemented in a separate file, the scripting can look like:

onmessage = function (e) {
var result = null;

    $.ajax({
        async: false,
        type: "POST",
        url: "/some/url?input=" + input,
        dataType: "json",
        retryLimit: 3,

        success: function (json) {
            result = json;
            postMessage({result: result});
        },

        error: function (xhr, err) {
            postMessage({error: err});
        }
    });

}
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • I'm just reading through it. Looks like this could be a solution. Thanks! – Dropout Oct 22 '14 at 08:59
  • Can I implement the worker as an anonymous function? You know.. something like `new Worker(function(){...});` – Dropout Oct 22 '14 at 09:08
  • answer: http://stackoverflow.com/questions/5408406/web-workers-without-a-separate-javascript-file – Dropout Oct 22 '14 at 09:16
  • 1
    @Dropout: the jsFiddle example shows how you can use an inline script tag, cf the answer you already found. I think you can also provide a string containing the necessary scripting for the `Blob`, something like `new Blob(['onmeessage= function() { /*... */}'], etc` – KooiInc Oct 22 '14 at 09:24
0

Depending on your use case you can use something like

task.js Simplified interface for getting CPU intensive code to run on all cores (node.js, and web)

A example would be

// turn blocking pure function into a worker task
const syncWorkerRequest = task.wrap(function (url) {
    // sync request logic
});

// run task on a autoscaling worker pool
syncWorkerRequest('./bla').then(result => {
    // do something with result
});

You should not be doing this though, unless you need to do some heavy data processing, please use async requests.

Chad Cache
  • 9,668
  • 3
  • 56
  • 48