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

标签 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>

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

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 的了解还不够,不知道如何解决这个问题。有人有什么想法吗?

最佳答案

如果用户打字速度很快,那么您可能会同时处理多个动画,并且不是动画的 .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();
    }
}

仅供引用,我还借此机会在同一个选择中使用多个项目,并使用 jQuery 链接来简化代码。

请参阅另一个答案,了解 jQuery 用于 ajax 调用的 .abort() 的讨论:

Abort Ajax requests using jQuery

关于JavaScript 对更新 DOM 元素的函数的异步调用重叠并导致问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30857059/

相关文章:

javascript - Amcharts 类别轴标签重叠

javascript - 以 Angular 5 滚动到类(class)

jquery - 如何解决数据表中 Shiny 的错位问题?

html - 如何获得与基表具有相同列宽的粘性表头

javascript - 将一个页面的 div 插入另一个页面

javascript - YouTube iframe api(现有的 iframe);无法让 iframe-api 工作

在 iframe 中使用替换方法的 Javascript

jquery - FullCalendar 和 MySQL——跨多个月的事件

javascript - 如何在 CSS 可见时将链接添加到 Tab 键顺序?

javascript - 如何使用 sencha-touch.jsb3 构建 Sencha Touch?