对更新DOM元素的函数的Javascript异步调用重叠并导致问题

时间:2015-06-16 00:30:12

标签: javascript jquery html ajax forms

背景信息:

我有一个要求输入邮政编码,州和城市的表格。在每个输入字段旁边,我有两个跨度,一个在输入良好时显示绿色复选标记,另一个在输入错误时显示红色x。当然,在任何给定时间只能看到一个。

<input type="text" id="Zip" class="form-control">
<span id="ZipOK" style="display:none;" class="glyphicon glyphicon-ok"></span>
<span id="ZipBad" style="display:none;" class="glyphicon glyphicon-remove"></span>

<input type="text" id="State">
<span id="StateOK" style="display:none;" class="glyphicon glyphicon-ok"></span>
<span id="StateBad" style="display:none;" class="glyphicon glyphicon-remove"></span>

<input type="text" id="City">
<span id="CityOK" style="display:none;" class="glyphicon glyphicon-ok"></span>
<span id="CityBad" style="display:none;" class="glyphicon glyphicon-remove"></span>

我有一个函数可以检测zip字段的输入,然后进行数据库调用以从邮政编码中获取州和城市并自动填写表单。

jQuery('.form-control').keyup(function(){
    validateZipcode();
});

这是执行ajax,自动填充州/城市并隐藏/显示适当反馈范围的功能。

function validateZip() {
    zip = $('#Zip').val();
    if (zip.length === 5 && $.isNumeric(zip)) {
        $.ajax({
            type:"POST",
            url: '?report=ajax&request=getStateAndCityFromZip',
            data:"Zip="+encodeURIComponent(zip),
            success: function(output) {
                output = $.parseJSON(output);
                if (output['State'].length > 0 && output['City'].length > 0) {
                    $('#State').val(output['State']);
                    $('#City').val(output['City']);
                    $('#StateOK').fadeIn();
                    $('#StateBad').hide();
                    $('#CityOK').fadeIn();
                    $('#CityBad').hide();
                    $('#ZipOK').fadeIn();
                    $('#ZipBad').hide();
                } else {
                    $('#ZipOK').hide();
                    $('#ZipBad').fadeIn();
                }
            },
            error: function (xhr, ajaxOptions, thrownError) {
            }});
    } else {
        $('#ZipOK').hide();
        $('#ZipBad').fadeIn();
    }
}

问题:

此代码按原样运行,但是在某些情况下,如果我非常快地输入邮政编码,#ZipBad#ZipGood跨度最终都会显示。以相对正常或缓慢的速度打字会导致预期的行为。

我认为这与对validateZip()的异步调用有关,但我对javascript知之甚少并不知道如何解决这个问题。有没有人有任何想法?

1 个答案:

答案 0 :(得分:3)

如果用户输入速度很快,那么您最终可能会同时处理多个动画,并且不是动画的.hide()将以错误的顺序进行,可能会以错误的显示结束。动画按顺序排队,.hide()并不会使事情失序。

还有一些边缘情况,你可能会同时在飞行中结束多个ajax调用,但这需要在zip字段中键入5个字符,然后快速退格并再次键入第五个字符,这可能会结束令人困惑的事情。

您可以在每次动画或可见性更改之前使用.stop(true)来阻止动画,以阻止任何当前正在运行的动画,并且可以通过取消之前的任何调用来防御多个ajax调用:

以下是实现此目的的一种方法:

var lastValidateAjax;
function validateZip() {
    var zip = $('#Zip').val();
    if (zip.length === 5 && $.isNumeric(zip)) {
        if (lastValidateAjax) {
            lastValidateAjax.abort();
        }
        lastValidateAjax = $.ajax({
            type:"POST",
            url: '?report=ajax&request=getStateAndCityFromZip',
            data: {Zip: zip},
            success: function(output) {
                lastValidateAjax = null;
                output = $.parseJSON(output);
                if (output.State.length > 0 && output.City.length > 0) {
                    $('#State').val(output.State);
                    $('#City').val(output.City);
                    $('#StateOK, #CityOK, #ZipOK').stop(true).fadeIn();
                    $('#StateBad, #CityBad, #ZipBad').stop(true).hide();
                } else {
                    $('#ZipOK').stop(true).hide();
                    $('#ZipBad').stop(true).fadeIn();
                }
            },
            error: function (xhr, ajaxOptions, thrownError) {
                lastValidateAjax = null;
            }
        });
    } else {
        $('#ZipOK').stop(true).hide();
        $('#ZipBad').stop(true).fadeIn();
    }
}

仅供参考,我也借此机会在同一个select中使用多个项目,并使用jQuery链来简化代码。

有关ajax调用的jQuery&#39; .abort()的讨论,请参阅此其他答案:

Abort Ajax requests using jQuery