ajax成功回调执行超出预期的顺序

时间:2012-10-17 22:35:17

标签: javascript jquery

我有一个函数可以在按下按钮时验证某些字段。首先检查用户名和密码是否可信。如果密码是适当安全的话。然后,如果它与确认密码框匹配。但是,似乎在第一个函数中的警报弹出之前,检查用户是否是真实的ajax似乎没有完成。

$(document).ready(function() {
    $('#submit_pw_ch').on('click', function(){

        var alertString = "Please correct the following errors: \n"
        //current username and password are correct
        var vUsr = valUsr();
        //new password is sufficiently secure
        var vPwd = valPwd();
        //confirmation of new password is same as previous box
        var sPwd = samePwd();

        console.log('valid user : ' + vUsr + '      valid password : ' + vPwd + '     same password : ' + sPwd);

        //append appropriate warnings to alert string
        if ( !vUsr ) { alertString += "-Your current username and password are invalid. \n"; }
        if ( !vPwd ) { alertString += "-The new password you have selected is not strong enough. \n"; }
        if ( !sPwd ) { alertString += "-The confirmation of your new password does not match the previous entry. \n"; }


        if ( !vUsr || !vPwd || !sPwd ) {
            alert(alertString);
            return false;
        } else {

            //change password

        }

    });
});

因此,检查该行的var vUsr = valUsr();调用

function valUsr() {

    var un = $('#uNameInput').val();
    var pw = $('#uPwdInput').val();
    //return value
    var validUsr = false;

    $.ajax({
        type: "post",
        url: "queries/confirm_user.php?<?=time()?>",
        data: "un=" + un + "&pw=" + pw,
        dataType: "json",
        success: function (returnedData) {
            console.log(returnedData)
            if (data == 'true') {
                validUsr = true;
            } else {
                validUsr = false;
            }
        } 

    });

    return validUsr;
}

不知怎的,虽然警报没有等待ajax完成获取它的数据。在我取消警告框后,console.log(returnedData)功能中的valUsr()出现在控制台中。为什么会这样?我该怎样预防呢?谢谢!

2 个答案:

答案 0 :(得分:2)

托马斯,

你需要迎合ajax固有的异步性,换句话说,你需要等到对ajax请求的响应已经到来,然后再决定做什么。

jQuery's Deferreds(和承诺)允许我们编写简单的代码,但Deferreds一开始往往会让你大吃一惊,至少非常轻微。

对于像这样的问题,没有独特的方法可以使用Deferreds,但这里只有一个。

$(document).ready(function() {
    $('#submit_pw_ch').on('click', function() {
        var form = this.form; //the form containing the submit button and the fields .

        //`alertArr` is an array to which messages will be added.
        var alertArr = ["Please correct the following errors:"];

        //`addAlert` will be called from a `Deferred.resolveWith(this, ...)` statement.
        //The context, `this`, is unused.
        function addAlert(index, txt) {
            alertArr[index] = txt;
        }

        //`compositeAction` will be called from a promise.done() statement.
        function compositeAction() {
            //first filter out null messages (ie. validation successes) from alertArr.
            var message = $.map(alertArr, function(txt, i){
                return txt || null;
            });
            if(message.length > 1) {
                //then alert the complete message with line breaks
                alert(message.join("\n"));
            } else {
                //submit the form to change the password
                //or another ajax call as required
                form.submit();
            }
        }

        // Invoke ajax validators and assign returned promises.
        // An index is passed, so the text messages can be displayed in a logical order, 
        // regardless of the order in which the validation promises are resolved.
        //If we didn't care about the order of the messages then the code would be slighly simpler.
        var vUsr = valUsr(0),
            vPwd = valPwd(1),
            sPwd = samePwd(2);

        //All validations adopt a similar pattern regardless of whether ajax is involved or not.
        //Here, we establish what is to be done when the promise are resolved, or
        //what is to be done immediately if the promise are alrady resolved.
        vUsr.done(addAlert);
        vPwd.done(addAlert);
        sPwd.done(addAlert);
        //At this stage, `addAlert` will contain entries for successful as well as unsuccessful validations. Successful entries will be filtered out by `compositeAction`

        //Establish what is to be done when all three promises are resolved.
        $.when(vUsr, vPwd, sPwd).done(compositeAction);

        //Return false unconditionally
        return false;
    });

    function valUsr(index) {
        var messages = {
            validated: '',//important - this message must be an empty string - do not change
            notValidated: '- Your current username and password are invalid.',
            ajaxError: '- Validation error: username and password.'
        };

        //Create a Deferred object, which will be resolved in response to several different outcomes.
        var def = $.Deferred();

        $.ajax({
            type: "post",
            url: "queries/confirm_user.php?<?=time()?>",
            data: {
                'un': $('#uNameInput').val(),
                'pw': $('#uPwdInput').val()
            },
            dataType: "json",
            success: function (returnedData) {
                if (returnedData == 'true') {
                    def.resolveWith(this, [index, messages.validated]);
                } else {
                    def.resolveWith(this, [index, messages.notValidated]);
                }
            },
            error: function() {
                def.resolveWith(this, [index, messages.ajaxError]);
            }
        });
        return def.promise();//Return a promise derived from the as yet unresolved Deferred.
    }

    function samePwd(index) {
        var pw1 = $('#uPwdInput').val();
        var pw2 = $('#uPwdInput2').val();
        var errMessage = (pw1 === pw2) ? '' : '-The confirmation of your new password does not match the previous entry';
        var def = $.Deferred();//Create a Deferred object, which will be resolved immediately
        def.resolveWith(this, [index, errMessage]);
        return def.promise();//Return a promise derived from the already resolved Deferred.
    }
});

valPwd()的格式与valUsr()samePwd()的格式相同,具体取决于是否涉及ajax。

答案 1 :(得分:1)

Ajax在运行中运行,同步

在成功回调中完成ajax请求后,您需要检查之后的其他字段的验证。您可以关闭同步请求,但浏览器将冻结'直到它获得一个,不建议。

您需要重新调整您的电话以反映这一点;我建议他们一旦完成输入密码并且字段模糊,就发送请求进行检查。这样,如果有任何错误,您将能够阻止表单结束时的等待时间。