好吧,我的标题不可能是真的,因为编程语言不能犯这样的错误,但它正在发生。所以我们可以肯定地说我的逻辑存在问题。
我有一段jQuery / JS代码,可以在进行AJAX调用之前检查“去”中的字符数,就像在SO的注释部分中一样。因此代码被认为是这样的:
如果输入中的字符数少于N,则将字符数减少(例如,2个字符要去,1个字符要去......)
Else 进行AJAX调用并在成功时显示结果。
当你第一次去表格时,这个过程顺利进行:
但是当我继续用退格(或删除)删除字符时,我再次在断点下(必须看到“N to go”)我再次显示“N to go”部分,但是AJAX即使它被包裹在else
中,呼叫也会通过!这很奇怪。结果如下:
红色文本是AJAX成功回调,黄色部分是字符计数器。
这是我的jQuery:
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$('#reg_email').keyup(function(){
var min_password_chars = 6;
var email_input = $('#reg_email').val();
var email_prev = '';
if (email_input.length < min_password_chars)
{
$('.email-check').text('');
if ($('.email-check').children('.yellowish').length == 0)
{
$('.email-check').append('<span class="yellowish"><span class="counter">6</span> to go</span>');
}
$('.email-check .counter').text(min_password_chars - email_input.length);
}
else
{
delay(function(){
$.ajax({
type: 'GET',
url: 'ajax.php?action=check_email',
data: { email: JSON.stringify(email_input) },
success: function(data){
var response = $.parseJSON(data);
$('.email-check').append(response.message);
email_prev += response.sent_email;
}
});
}, 1500);
if (email_input != email_prev)
{
$('.email-check').text('');
}
}
});
这是HTML:
<div class="form-group">
<label for="rep_email">Repeat email</label>
<input type="email" class="form-control" id="rep_email" name="email_rep" placeholder="Enter your email" required>
<p class="email-check pull-right validate-note"><span class="yellowish"><span class="counter">6</span> to go</span></p>
</div>
我可能做错了什么?我的逻辑在哪里失败了?
答案 0 :(得分:1)
你的ajax调用是双重异步的,这可能是你的调试和结果混乱的原因。这种类型的东西实际上很难用断点调试。我发现我经常要在代码中放置console.log()
语句,以便我可以实时查看实际的事件序列。
else
子句的执行部分在首次遇到else
子句之后的某个时间执行,并且由于您的delay()
和AJAX调用的异步性质而导致它被双倍延迟。这使得调试变得困难,并且如果您没有为特定情况编码,则很容易导致编程错误。
首先,它们是异步的,因为您使用的delay()
我认为是setTimeout()
。这意味着你甚至不会在一段时间之后启动ajax调用。其次,它们是异步的,因为它们是异步的ajax调用。因此,他们在else
分支执行之后的某个时间调用成功处理程序。实际上,您可以在完成执行之前键入其他字符。
您也有关闭问题,您可能在成功处理程序中使用的数据与最初发送ajax调用时的数据不同(因为自ajax调用以来它已经更改)。
在下面的代码中,我应用了以下修补程序:
当你安排下一个ajax调用时,这不会取消任何inflight ajax调用,但这只是服务器效率的事情,而不是正确性的事情。您的代码还假定将同时处理并返回多个在飞行中的ajax调用。这在实际世界中通常就是这种情况,但如果没有专门的命令就不能保证。
var emailTimeout;
$('#reg_email').keyup(function(){
var min_password_chars = 6;
var email_input = $('#reg_email').val();
var email_prev = '';
if (email_input.length < min_password_chars)
{
$('.email-check').text('');
if ($('.email-check').children('.yellowish').length == 0)
{
$('.email-check').append('<span class="yellowish"><span class="counter">6</span> to go</span>');
}
$('.email-check .counter').text(min_password_chars - email_input.length);
}
else
{
clearTimeout(emailTimeout);
emailTimeout = setTimeout(function(){
// get latest email value, might have changed
var latest_email_input = $('#reg_email').val();
// if it's not long enough, don't send to the server
if (latest_email_input.length < min_password_chars) return;
$.ajax({
type: 'GET',
url: 'ajax.php?action=check_email',
// always retrieve latest value of data (may have changed)
data: { email: JSON.stringify(latest_email_input) },
success: function(data){
var response = $.parseJSON(data);
$('.email-check').append(response.message);
email_prev += response.sent_email;
}
});
}, 1500);
if (email_input != email_prev)
{
$('.email-check').text('');
}
}
});
仅供参考,这是你的酷炫延迟功能的一个更多功能的版本,可以通过传递不同的标签字符串用于不同的用途,同时用于多种不同的用途:
var delay = (function(){
var timers = {};
return function(tag, callback, ms){
clearTimeout(timers[tag]);
timers[tag] = setTimeout(function() {
delete timers[tag];
callback();
}, ms);
};
})();
// sample usage
delay("emailKey", fn, 1500);
delay("search", fn, 500);
答案 1 :(得分:1)
它似乎是一种竞争条件,由$.ajax
和delay()
组合而成。您的ajax调用在事件循环的下一个滴答之前不会触发,因此在退出if块后将附加ajax返回的消息。
我会做以下事情:
以下是我将如何重写它:
$('#reg_email').keyup(_.debounce(function() {
$('.email-check').text('');
var min_password_chars = 6;
var email_input = $('#reg_email').val();
var email_prev = '';
if (email_input.length < min_password_chars) {
if ($('.email-check').children('.yellowish').length == 0) {
$('.email-check').append('<span class="yellowish"><span class="counter">6</span> to go</span>');
}
$('.email-check .counter').text(min_password_chars - email_input.length);
} else {
$.ajax({
type: 'GET',
url: 'ajax.php?action=check_email',
data: { email: JSON.stringify(email_input) },
success: function(data){
var response = $.parseJSON(data);
$('.email-check').append(response.message);
email_prev += response.sent_email;
}
});
}
}), 1500);
答案 2 :(得分:1)
假设您在电子邮件字段中输入abcdefgh
,然后在其上退格,这将导致5个ajax调用,由于delay
而分布至少5 * 1.5 = 7.5秒。
要计算,请从abcde
开始:
abcde
- 什么都没有。abcdef
- ajax call 1 abcdefg
- ajax call 2 abcdefgh
- ajax call 3 abcdefg
- ajax call 4 abcdef
- ajax call 5 在编辑字段后,ajax调用将继续,并且它们之间至少有1.5秒。
此外,如果您正在使用断点,那么当您暂停程序时,这将暂停延迟。当你再次运行它时,它将从它停止的地方继续,排队的ajax事件,使它看起来像是自己运行,但实际上是从上次运行中遗留下来。