背景信息:
我有一个要求输入邮政编码,州和城市的表格。在每个输入字段旁边,我有两个跨度,一个在输入良好时显示绿色复选标记,另一个在输入错误时显示红色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知之甚少并不知道如何解决这个问题。有没有人有任何想法?
答案 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()
的讨论,请参阅此其他答案: