即使在jQuery中没有满足条件,也执行了我的else语句

时间:2013-12-14 00:40:13

标签: javascript html ajax jquery

好吧,我的标题不可能是真的,因为编程语言不能犯这样的错误,但它正在发生。所以我们可以肯定地说我的逻辑存在问题。

我有一段jQuery / JS代码,可以在进行AJAX调用之前检查“去”中的字符数,就像在SO的注释部分中一样。因此代码被认为是这样的:

如果输入中的字符数少于N,则将字符数减少(例如,2个字符要去,1个字符要去......)
Else 进行AJAX调用并在成功时显示结果。

当你第一次去表格时,这个过程顺利进行:

  • 你得到空场
  • 开始输入
  • 角色指示器不断减少
  • 我们点击停止检查的“断点”
  • 进行AJAX调用
  • 我们收到成功回拨
  • 上显示的消息

但是当我继续用退格(或删除)删除字符时,我再次在断点下(必须看到“N to go”)我再次显示“N to go”部分,但是AJAX即使它被包裹在else中,呼叫也会通过!这很奇怪。结果如下:

AJAX failure

红色文本是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>

我可能做错了什么?我的逻辑在哪里失败了?

3 个答案:

答案 0 :(得分:1)

你的ajax调用是双重异步的,这可能是你的调试和结果混乱的原因。这种类型的东西实际上很难用断点调试。我发现我经常要在代码中放置console.log()语句,以便我可以实时查看实际的事件序列。

else子句的执行部分在首次遇到else子句之后的某个时间执行,并且由于您的delay()和AJAX调用的异步性质而导致它被双倍延迟。这使得调试变得困难,并且如果您没有为特定情况编码,则很容易导致编程错误。

首先,它们是异步的,因为您使用的delay()我认为是setTimeout()。这意味着你甚至不会在一段时间之后启动ajax调用。其次,它们是异步的,因为它们是异步的ajax调用。因此,他们在else分支执行之后的某个时间调用成功处理程序。实际上,您可以在完成执行之前键入其他字符。

您也有关闭问题,您可能在成功处理程序中使用的数据与最初发送ajax调用时的数据不同(因为自ajax调用以来它已经更改)。


在下面的代码中,我应用了以下修补程序:

  1. 取消之前尚未解雇的任何计时器,这样当您输入更多字符时,您就不会让计时器继续前进和前进。当您即将安排另一个呼叫时,这将阻止发送ajax呼叫。
  2. 始终将最新值发送到服务器,即使自最初设置计时器以来已对其进行了修改。
  3. 如果由于此计时器已设置并且现在太短而已被修改,请不要将其发送到服务器,因为已经报告了太短的错误。
  4. 当你安排下一个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)

它似乎是一种竞争条件,由$.ajaxdelay()组合而成。您的ajax调用在事件循环的下一个滴答之前不会触发,因此在退出if块后将附加ajax返回的消息。

我会做以下事情:

  1. 去抖动事件处理程序(如果它是给定时间窗口内的最后一个事件,则仅调用事件处理程序)。尝试使用underscore.js's debounce,这对于这种情况非常有用。
  2. 将帮助文本清除函数移动到事件处理程序的顶部(不需要复制该代码)
  3. 以下是我将如何重写它:

    $('#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事件,使它看起来像是自己运行,但实际上是从上次运行中遗留下来。