javascript - ajax 成功回调不按预期顺序执行

标签 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 完成获取数据。在我关闭警报框后,valUsr() 函数中的 console.log(returnedData) 出现在控制台中。为什么会发生这种情况?我该如何预防?谢谢!

最佳答案

托马斯,

您需要考虑 ajax 固有的异步性,换句话说,您需要等到 ajax 请求的响应到达后再决定要做什么。

jQuery's Deferreds (和 promise )允许我们编写简单的代码,但 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 或不是。

关于javascript - ajax 成功回调不按预期顺序执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12944454/

相关文章:

javascript - 是否可以在 JavaScript 中为剩余变量设置默认参数?

jquery 选择器和单击事件不起作用

jquery - 使用 Material 设计精简版创建星级

jquery - Html 文本区域占位符

javascript - 如果我在点击相应链接之前先滚动页面,弹出窗口会出现在错误的位置

javascript - 是否可以将许多图像放入灯箱但只显示一张图像以激活它们?

javascript - Bookshelfjs + bcrypt hashPassword 可以创建但不能更新

Javascript,改变对象值

javascript - 文本框切换 JQuery

jquery - Trent Richardson 的日期时间选择器未显示时间选择器