Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can javascript be stopped to wait for a deferred to finish?

Tags:

jquery

I have a function which takes a parameter and does synchronous loadings.

I changed it to do an asynchronous jQuery.ajax call to retrieve data and call a callback. Old code (which cannot be modified) uses the same function and fails. I need to be able to retrieve the data both ways so async code can keep on running and old sync code can retrieve the cached data if async already loaded it, load it synchronously or wait for any async requests which are already running.

var ajaxQueries = {}
loadEngineData(fileId, callback) {
    var sync = callback == undefined;
    if (ajaxQueries[fileId]) {
        if (sync) {
            //Need to stop here and wait for ajaxQueries[fileId] to finish
            //Execution cannot continue! If we return before defered has ended here 3rd party scripts will fail.
            return data;
        }
        else {
            ajaxQueries[fileId].done(function(data){callback(data)});
        }
    }
    else {
        ajaxQueries[fileId] = $.ajax({
            async:!sync,
            type:'GET',
            url:fileId2Name(fileId),
            data:null,
            dataType:'text',
        });
        if (sync) {
            var _data = undefined;
            ajaxQueries[fileId].done(function(data){_data=data});
            return _data;
        }
        ajaxQueries[fileId].done(function(data){callback(data);});
    }
}

If an old script calls the function the ajax query will run synchronously and all subsequent calls will use the deferred .done and .fail and everything will be fine.

var enginePhyData = loadEngineData('physics');
//Do stuff

If a new script calls the function first and during this loading an old script tries to load data from the same file, I end with a situation where the deferred ajax query in ajaxQueries[fileId] is running asynchronously and I have to wait for it to finish loading the data to avoid breaking the existing libs.

I simplified loadEngineData to keep the question focussed. Otherwise it's a bit more complex and allows calling a list of files to load in parallel

loadEngineData(['geometry', 'scripts'], function() {
    var phy = loadEngineData('physics');
    var geo = loadEngineData('geometry');
    var scr = loadEngineData('scripts');

    //run the async function;
});
loadEngineData('physics', function() {
    //run the async function;
});

//...
//in the scripts file

var phy = loadEngineData('physics');
//here phy might be undefined if this file went through eval() before `loadEngineData('physics',...)` was called;

I could modernize the code, but the issue is that some files are shared across projects and run in different environments. I can't currently modify the old scripts without forking the dependencies.

like image 717
Coyote Avatar asked Jan 21 '13 17:01

Coyote


1 Answers

You cannot stop the execution of javascript while waiting for some asynchronous ajax call to finish. Javascript simply doesn't work that way.

Instead, you have to rework the way you program so that code that wants to wait for an asychronous ajax call to be completed will execute via a callback function, not synchronously after the ajax call executes.

like image 86
jfriend00 Avatar answered Oct 03 '22 08:10

jfriend00