views:

161

answers:

4

I have an Ajax call that currently needs to be synchronous. However, while this Ajax call is executing, the browser interface freezes, until the call returns. In cases of timeout, this can freeze the browser for a significant period of time.

Is there any way to get the browser (any browser) to refresh the user interface, but not execute any Javascript? Ideally it would be some command like window.update(), which would let the user interface thread refresh.

If this would be possible, then I could replace the synchronous AJAX call with something like:

obj = do_async_ajax_call();
while (!obj.hasReturned()) {
  window.update();
}
// synchronous call can resume

The reason that I can't use setTimeout, or resume a function in the callback, is that the execution flow cannot be interrupted: (there are far too many state variables that all depend on each other, and the long_function() flow would otherwise have to be resumed somehow):

function long_function() {
   // lots of code, reads/writes variable 'a', 'b', ...
   if (sync_call_is_true()) {
     // lots of code, reads/writes variable 'a', 'b', ...
   } else {
     // lots of code, reads/writes variable 'a', 'b', ...
   }
   // lots of code, reads/writes variable 'a', 'b', ...
   return calculated_value;
}
A: 

Take the rest of the call and put it in the callback that is called when the result comes back. I seriously doubt that this would be completely impossible for you to do. Any logic you need to put in the call can be duplicated in the callback

Allen
A: 

asynchronous ajax fetch then settimeout and do the processing work in chunks (triggered by the callback)

PeanutPower
+3  A: 

You need to replace your synchronous request with an asynchronous request and use a callback. An oversimplified example would be:

obj = do_async_ajax_call(function (data, success)
{
    if (success) 
    {  
        // continue...  
    } 
}); 

function do_async_ajax_call(callback)
{
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://mysite.com", true);
    xhr.onreadystatechange = function ()
    {
        if (xhr.readyState == 4 && xhr.status == 200)
            callback(xhr.responseXML, true);
        else if (xhr.readyState == 4)
            callback(null, false);
    }
    xhr.send();
}

This way you're passing an anonymous function as a parameter to the ajax requesting function. When the ajax is complete, the function that was passed is called with the responseXML passed to it. In the meantime, the browser has been free to do it's usual thing until the call completes. From here, the rest of your code continues.

Andy E
This would normally be sufficient, but I can't split up the operation flow (as updated in the question). I am trying another approach now...
jevon
It's *always* possible to split it up; this is the CPS transform (look up “continuation-passing style”; the continuation parameter is your callback). Your local state variables are simply closed over in the callback function. Loops become recursive calls. It's not that hard or obscure once you get the hang of it.
Kevin Reid
I agree it's always possible, but in this case it wasn't the best solution (there were too many state variables!) :) In the end, I used the result of previous callbacks (or regular server polling) to update the client-side with a cached value of the synchronous call when necessary, so it doesn't need to call Ajax at all.
jevon
A: 

JavaScript is single-thread. So by definition, you cannot update UI while you are in a tide loop. However, starting from Firefox 3.5 there's added support for multi-threaded JavaScripts called web workers. Web workers can't affect UI of the page, but they will not block the updates of the UI either. We workers are also supported by Chrome and Safari.
Problem is, that even if you move your AJAX call into background thread and wait of execution to complete on it, users will be able to press buttons and change values on your UI (and as far as I understand, that's what you are trying to avoid). The only thing I can suggest to prevent users for causing any changes is a spinner that will block the entire UI and will not allow any interaction with the page until the web-call returns.

Ilya Volodin
I don't mind if users interact with the page (and the interaction is queued up); but currently, while a synchronous Ajax call is executing in Firefox, the entire browser freezes. This is what I want to prevent.
jevon