Using deferred with jquery ajax calls and async pr

2019-09-05 13:27发布

Background
This is in continuation to my question Correct way to set up a sequence of synchronous/asynchronous functions all of which can stop form submission and further processing?

I got the answer on what was the correct way (deferred pipe), but I am still not able to actually implement this. I just started reading on jquery deferred API today and I could not grasp much yet. The jQuery API documentations seem too complicated with little example. Could anyone put links to some basic demos/tutorials regarding this? I need a kick-start here.

Details
I have jquery version 1.6 being used in this project.

Consider this example - When user clicks form submit button -
1. Run validateInventory().
a. If validation fails, display a confirmation dialog to user, if user agrees (go to step 2)
Or
b. If validation passes (go to step 2)
2. run preValidateUrls().
a. If validation fails, display a confirmation dialog to user, if user agrees (go to step 3)
Or
b. If validation passes (go to step 3)
3. Submit the form.

Following is the structure of the asynchronous functions that I have -

Note that this function also has a if(confirm) block inside. Read my Question 2.

    function validateInventory()
    {
         $.ajax({
           type: "POST",
           url: posturl+"?"+params,
           dataType: "json",
           success: function(res)
               { 
                     if(!res.success)
                     {
                          //display some confirmation dialog, if user agrees con
                          if(confirm(msg)) 
                          {
                                //continue with next validation step 
                          }
                     }  
                     else
                     {
                          //validation success - so continue with next validation step
                     }  
                }
            });
    }

    //similar logic as inside validateInventory()
    function preValidateUrls()
    {


    }

I may also have some synchronous validation function (client-side-only logic) in the validation logic, anywhere in the sequence -

function syncVal()
{
    return true/false
}

Question 1 Should the syntax for putting such functions also be similar to the asynchronous functions?

Question 2 How do I handle the display of showing confirmation dialog (if validation fails) and proceed to next validation step only if user confirms. Should there be some restructuring of the function? The if(confirm) block needs to be moved outside?

Where I have reached so far

Well nothing much, I guess I need to use .when, .done APIs.

1条回答
够拽才男人
2楼-- · 2019-09-05 14:06

If I understand Steps 1,2,3 correctly, then the logic you want can be coded something like this :

$(function() {
    function validateInventory(form) {//`form` is passed conventionally at the left hand end of the pipe chain.
        var dfrd = $.Deferred();//A Deferred object to be resolved/rejected in response to ajax success/error.
        var params = .....;//use values from `form` as required
        $.ajax({
            type: "POST",
            url: posturl + "?" + params,
            dataType: "json"
        }).done(function(res) {//ajax success
            if(res.success || confirm(msg1)) { dfrd.resolve(form); }//Here we resolve dfrd, passing `form` in order to make `form` available to the next function in the pipe chain.
            else { dfrd.reject("validateInventory() failed (not verified)"); }//Application error. By rejecting with a specific message, we have the means of knowing where the failure occurred.
        }).fail(function(jqXHR, textStatus, errorThrown) {//ajax error
            dfrd.reject("validateInventory() failed (textStatus)");//Again, a specific message.
        });
        return dfrd;
    }

    //Similar logic as inside validateInventory()
    function preValidateUrls(form) {//The form, is piped through by the statement `dfrd.resolve(form);` in validateInventory
        var dfrd = $.Deferred();
        var params = .....;
        $.ajax({
            type: "POST",
            url: posturl + "?" + params,
            dataType: "json"
        }).done(function(res) {
            if(res.success || confirm(msg2)) { dfrd.resolve(form); }
            else { dfrd.reject("preValidateUrls() failed (not verified)"); }
        }).fail(function(jqXHR, textStatus, errorThrown) {
            dfrd.reject("preValidateUrls() failed (textStatus)");
        });
        return dfrd;
    }

    //This is the function to be called if the various stages of validation were successful.
    function overallSuccess(form) {
        form.submit(); 
    }

    //This is a common error handler, which will be called if either of the validation stages fail.
    function errorHandler(message) {
        alert(message);//or whatever
    }

    var myForm = $("form").get(0);//for example

    //And now the glue that puts the component parts together.
    validateInventory(myForm).pipe(preValidateUrls, errorHandler).pipe(overallSuccess, errorHandler);
});

untested

For explanation, see comments in code.

The whole thing can be factored any number of different ways. I would choose to code it as above because the component parts are separate and clear, and the "glue" statement (the pipe chain) is very concise and easy to extend to accommodate further validation steps. With other approaches, you tend to get deep nesting of functions which is hard to follow, especially for someone who has to maintain the code in the future.

查看更多
登录 后发表回答