如果Javascript函数再次被调用,如何终止它?

如果Javascript函数再次被调用,如何终止它?,javascript,function,terminate,debouncing,Javascript,Function,Terminate,Debouncing,我的网页上有一个搜索框,其中有复选框,以便用户过滤其结果。一次只能选中一个复选框 单击复选框后,我的代码将运行,并将筛选器应用于列表并返回正确的结果 我遇到的问题是,当一个复选框被快速连续单击多次时,它会对请求进行排队,并逐个将其撤回。如果选中某个复选框,然后多次取消选中,这可能需要一段时间 Javascript中是否有任何方法通知函数它已被再次调用,并且应该停止除最后一个请求之外的所有请求 您想将onclick回调封装在一个去抖动函数中,如 说你有这个 function search() {

我的网页上有一个搜索框,其中有复选框,以便用户过滤其结果。一次只能选中一个复选框

单击复选框后,我的代码将运行,并将筛选器应用于列表并返回正确的结果

我遇到的问题是,当一个复选框被快速连续单击多次时,它会对请求进行排队,并逐个将其撤回。如果选中某个复选框,然后多次取消选中,这可能需要一段时间


Javascript中是否有任何方法通知函数它已被再次调用,并且应该停止除最后一个请求之外的所有请求

您想将
onclick
回调封装在一个去抖动函数中,如

说你有这个

function search() {
    // ...
}

$jquery(".myFilterCheckboxes").click(search);
您应该能够将上述内容更改为:

// Only allow one click event / search every 500ms:
$jquery(".myFilterCheckboxes").click(_.debounce(search, 500));
有大量的去Bouncing函数,如果您不能或不想包含下划线.js,那么编写自己的函数并不是什么大问题

我的第一个想法是去Bouncing,因为你提到多次点击可以在短时间内创建多个事件。去Bouncing通常用于诸如键入前搜索或自动完成之类的操作,以便在按键之间留出一点思考时间

正如其他人所提到的,在搜索运行时简单地禁用复选框/单击事件可能更有意义。在这种情况下,请尝试以下操作:

function disableClick(elem) {
  elem.unbind("click");
  elem.attr("disabled", true);
}

function enableClick(elem, onclick) {
  // Enable click events again
  elem.live("click", search);
  // Enable the checkboxes
  elem.removeAttr("disabled");
}

function search() {
  var boxes = $jquery(".myFilterCheckboxes");
  disableClick(boxes);
  $.get(...).always(function() {
    enableClick(boxes, search);
  });
}

$jquery(".myFilterCheckboxes").live("click", search);
为什么要禁用click事件,将disabled属性添加到复选框中,而不仅仅是一个全局锁变量?全局锁可能有点容易出错,但除此之外,我们已经有了一个在DOM中很重要的全局对象。如果我们只是修改DOM状态,我们就得到了正确的行为,并向用户发出信号,让他们在搜索完成之前都不要犹豫


也就是说,在任何类型的锁定/解除绑定场景中,向用户指示加载微调器或您正在进行的工作都可能是有意义的。

您可以使用锁定模式:

HTML

在本例中,无论单击复选框多少次,函数只运行一次,直到超时2秒后释放锁为止

这种模式非常好,因为它在释放锁时为您提供了控制权,而不是依赖于像“去盎司”这样的定时间隔。例如,它将与Ajax一起工作。如果您的复选框触发Ajax调用以进行过滤,您可以:

  • 第一次单击时,设置锁定
  • 调用Ajax端点。后续单击不会调用Ajax端点
  • 在Ajax成功函数中,重置锁
  • 现在可以再次单击复选框
  • HTML


    这里的问题是复选框被反复单击。您应该在处理时禁用复选框(这也会禁用元素上的单击事件),然后在处理完成后重新启用复选框

    去抖动是个好主意,但您并不总是知道处理函数需要多长时间才能完成

    下面是一个简单的示例,使用jquery promise在一些处理之后重新启用复选框

    使用以下代码:

    function processStuff() {
        var dfd = $.Deferred();
    
        // do some processing, when finished, 
        // resolve the deferred object
        window.setTimeout(function(){
            dfd.resolve();
        }, 2000);
    
        return dfd.promise();
    }
    
    function startProcessing() {
        $('#processingCheckbox').attr('disabled', 'disabled');
         var promise = processStuff();    
        promise.done(enableCheckbox);
    }
    
    function enableCheckbox() {
        $('#processingCheckbox').removeAttr('disabled');
    }
    
    $('#processingCheckbox').on('click', startProcessing);
    

    如果“一次只能选中一个复选框”,则应使用单选按钮而不是复选框为什么不在执行检查时设置一个变量?是否可以禁用onclick处理程序中的复选框,然后在ajax调用返回时重新启用它?@Lloyd添加一个无过滤器单选按钮选项?非常适合我的需要,谢谢你的回答。我甚至都不知道“脱发”这个词。再次感谢在这种情况下,我认为您应该将immediate参数传递为true,以使debounce在等待间隔的前缘而不是后缘触发函数。是的,去抖动更适合处理按键事件(键入时自动完成/搜索)用例。
    function_lock = false
    
    fire = function() {
        // First, check the lock isn't already reserved. If it is, leave immediately.
        if (function_lock) return;
    
        // We got past the lock check, so immediately lock the function to 
        // stop others entering
        function_lock = true;
    
        console.log("This message will appear once, until the lock is released")
    
        // Do your work. I use a simple Timeout. It could be an Ajax call.
        window.setTimeout(function() {
            // When the work finishes (eg Ajax onSuccess), release the lock.
            function_lock = false;
        }, 2000);
    }
    
    <input type="checkbox" onclick="doAjax()" >CB2
    
    ajax_lock = false
    
    doAjax: function() {
        // Check the lock.
        if (ajax_lock) return;
    
        // Acquire the lock.
        ajax_lock = true;
    
        // Do the work.
        $.get("url to ajax endpoint", function() {
             // This is the success function: release the lock
             ajax_lock = false;
        });   
    } 
    
    function processStuff() {
        var dfd = $.Deferred();
    
        // do some processing, when finished, 
        // resolve the deferred object
        window.setTimeout(function(){
            dfd.resolve();
        }, 2000);
    
        return dfd.promise();
    }
    
    function startProcessing() {
        $('#processingCheckbox').attr('disabled', 'disabled');
         var promise = processStuff();    
        promise.done(enableCheckbox);
    }
    
    function enableCheckbox() {
        $('#processingCheckbox').removeAttr('disabled');
    }
    
    $('#processingCheckbox').on('click', startProcessing);