5

The jQuery docs strongly urge you not to set async to false when performing an $.ajax request.

However, I'm seeing common solutions to synchronicity problems involve doing just this. And then I've seen people been chastised for going against the docs' recommendation.

With that said, I have attempted to use a promise to avoid using async:false with no luck.

Here is the code I'm using. I have an onclick event that calls addToOrder:

function saveTemplate() {
    var formData = getFormData();
    return $.ajax({
        type: "POST",
        url: "/p/session/save/" + sessionid + "/template/<?php echo $templateID ?>/",
        data: formData,
        async: true,
        success: function(msg){
            var rsp = $.parseJSON(msg);
            if (rsp.response === 'Saved') {
                sessionid = rsp.sessionid;
                $("#save-preview-data-response").html("&nbsp;&nbsp;&nbsp;" + rsp.response).fadeIn(100).delay(1000).fadeOut(1000);
            } else {
                $("#save-preview-data-response").css('color','#ff0000').html("&nbsp;&nbsp;&nbsp;" + rsp.response).fadeIn(100).delay(1000).fadeOut(1000);
            }
        }
    });
}

function addToOrder() {
    var saved = saveTemplate();
    var issaved;
    saved.success(function(e) {
        var rsp = $.parseJSON(e);
        issaved = (rsp.response == 'Saved') ? true : false;
    });
    if(issaved) {
        $.ajax({
            type: "POST",
            url: "<?php echo $baseURL; ?>addToOrder/respond/json",
            data: "sid=" + sessionid,
            async: true,
            success: function(msg){
                var rsp = $.parseJSON(msg);
                if (rsp.response === 'Saved') {
                    alert(msg);
                }
            }
        });
    }
}

issaved will always evaluate to false, as it is being evaluated before saveTemplate has had time to run. The only solution I have found is to set async:false but I am taking the warnings I've seen serious and would rather not. What other solutions are there?

Community
  • 1
  • 1
Nick
  • 2,872
  • 3
  • 34
  • 43

3 Answers3

12

Tactics to avoid using async:false with jQuery?

Learn to love callbacks. :-) When people do this:

// The synchronous way
function doSomething() {
    var foo;
    $.ajax({
        url: "/the/url",
        async: false,
        success: function(response) {
            foo = response.foo;
        }
    });
    return foo;
}

// ...somewhere else, we use it
function flurgle() {
    var bar = /* go get `bar` from somewhere */;
    var x = 52;

    if (doSomething() === bar) {
        x -= 10;
    }
    niftyFunctionUsing(x);
}

...the event-driven, asynchronous way really isn't that much different:

// The asynchronous way
function doSomething(callback) {
    $.ajax({
        url: "/the/url",
        success: function(response) {
            callback(response.foo);
        }
    });
}

// ...somewhere else, we use it
function flurgle() {
    var bar = /* go get `bar` from somewhere */;
    var x = 52;

    doSomething(function(foo) {
        if (foo === bar) {
            x -= 10;
        }
        niftyFunctionUsing(x);
    });
}

Since callbacks frequently involve closures (the above ones do, that's how we're accessing x and bar), this article from my blog may be helpful: Closures are not complicated

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Yeah, that's what I was trying to say. You beat me to writing the code though. I did nearly get confused by failing to notice your doSomething in the second example was accepting the callback as a function. ;-) – Chris Aug 01 '11 at 17:50
  • 1
    Fantastic answer! Even more than 8 years ago, i salute you – Gobbin Oct 03 '19 at 09:30
1

You could change the SaveTemplate function to accept a parameter that is a function that is run on save. Then in your addToOrder function you can either generate an anonymous function with the code you have in there or refactor so that most of that code is in another function that you can pass by name.

The idea is that with async code the moment you make an async call you stop working on that issue there (ie the save code) and pick up running in your callback. You could keep doing unrelated stuff after the async call (eg putting up a message to the user sayign "please wait") but any further code related to the save must be in a function triggered by the callback set in the success property of the ajax configuration.

Chris
  • 27,210
  • 6
  • 71
  • 92
0

Put the second .ajax() call inside of the .success() function of the first.

evan
  • 4,239
  • 1
  • 18
  • 18
  • `saveTemplate` is used elsewhere and is not solely coupled to `addToOrder` (E.g. A user in my application can save their progress at any time, which calls `saveTemplate` -- however, when they submit their 'order' I save their work one last time then proceed with adding their template to an order. – Nick Aug 01 '11 at 17:42
  • Not the main .success() then, the one inside of `.addToOrder()` where you've also got `issaved = (rsp.response == 'Saved') ? true : false;`. – evan Aug 01 '11 at 17:46