jQuery事件只在每个时间间隔内发生一次

5
$(document).ready(function() {

    $('#domain').change(function() {

        //

    });

});

change函数的代码基本上会发送ajax请求来运行一个PHP脚本。#domain是一个文本输入框。因此,我想做的就是在用户在文本字段中输入一些文本时(例如搜索建议),发送ajax请求。
然而,我想设置一个时间间隔以减轻PHP服务器的负载。因为如果jQuery每次用户向文本字段添加另一个字母时都发送AJAX请求,它将消耗大量带宽。
因此,我想设置2秒作为间隔时间。每当用户键入一个字母时,将触发一次AJAX请求,但最高频率为2秒。
我该怎么做?

请参考以下两个网址:http://stackoverflow.com/questions/1715399/javascript-trigger-an-event-that-happens-in-a-few-seconds-but-be-able-to-cancel 和 https://dev59.com/DHI-5IYBdhLWcg3w48_k。 - Crescent Fresh
6个回答

10
$(function() {
  var timer = 0;
  $("#domain").change(function() {
    clearTimeout(timer);
    timer = setTimeout(function(){
      // Do stuff here
    }, 2000);
  });
});

7
$(document).ready(function() {

    var ajaxQueue;

    $('#domain').change(function() {

        if(!ajaxQueue) {
           ajaxQueue = setTimeout(function() { 
              /* your stuff */
              ajaxQueue = null;
          }, 2000);
        }

    });

});

这就是它的亮点,它在setTimeout中被定义。在此之前它将是未定义的(因此为假值)。这实际上与在$(document).ready(...)之前写入var ajaxQueue = null;是一样的。 - rfunduk
这实际上是一个非常优雅的解决方案。绝对比跟踪事件之间的毫秒数更好。 - Vincent Ramdhanie
哦,用这段代码ajax调用没有被执行过。 - Richard Knop
@thenduks:不,它从未被声明,因此它会最终进入window对象,这是一个坏习惯。 - Svante Svenson
@svinto:如果引入变量时没有使用“var”,那么它将成为全局变量。这与将其放入窗口对象中是相同的,但这正是JS中全局变量的定义。如果您在代码的全局范围内编写var a ='test';,则还可以通过window.a访问它。这是相当标准的做法,我不能说这是一件坏事,但当然,它不是非常自我记录的代码。 - David Hedlund
@eduncan911:实际上它会触发多次。一旦它被触发,它将设置为null,这意味着下一次“change”被触发时,“ajaxQueue”将为falsey,并且将设置新的超时。但如果它没有被触发,它将不会注册新的超时,这正是期望的结果。 - David Hedlund

5

实际上,您需要检查自上次更改事件以来的时间,以便跟踪事件之间的毫秒数,而不是每2秒调用一次。

$(document).ready(function() {

    var lastreq = 0; //0 means there were never any requests sent
    $('#domain').change(function() {
         var d = new Date();
         var currenttime = d.getTime(); //get the time of this change event
         var interval = currenttime - lastreq; //how many milliseconds since the last request
         if(interval >= 2000){ //more than 2 seconds
            lastreq = currenttime; //set lastreq for next change event
            //perform AJAX call
         }

   });

});

这个需要一个清理函数来将最后的更新发送到服务器吗? - Bell
@Bell不是这样的。它与更改事件绑定,因此如果此更改事件距上次更改事件超过2秒,则发送调用,否则它将忽略该事件。虽然我认为@d的解决方案更简洁,这也是我会选择的方案。 - Vincent Ramdhanie
如果我输入了两个字符,但第二个字符在不应该发送的时间内被按下,那该怎么办?但是我并没有输入第三个字符来再次触发它,该怎么办? - Ape-inago

1

脑海中想到的,没有在浏览器中尝试过。大概是这样:

$('#domain').change(function() {

    if (!this.sendToServer) { // some expando property I made up
        var that = this;
        this.sendToServer = setTimeout(function(that) {
            // use "that" as a reference to your element that fired the onchange.
            // Do your AJAX call here
            that.sendToServer = undefined;
        }, yourTimeoutTimeInMillis)
    }
    else {
        clearTimeout(this.sendToServer);
    }
});

1

两个变量:charBuffer,sendFlag

  1. 使用setTimeout函数每两秒钟调用一次一个函数。
    • 此函数检查缓冲区是否有内容。
    • 如果有,发送/清空内容并将已发送标志(设置为false)清除。
      • 它还应该清除超时并重新设置它
    • 否则就设置标志(设置为true)。
  2. 每当用户按下键时,都将其存储在缓冲区中。
    • 如果已发送标志清除(即为false),则不执行任何操作。
    • 否则(为true),发送/清空当前在缓冲区中的内容并将标志清除(设置为false)。
      • 它还应该清除超时并重新设置它

这样做可以使您第一次按键时发送,必须等待至少2秒才能再次发送。

可能需要进行一些微调,但我使用此设置来执行类似的操作。


在这种情况下,文本输入字段可以是缓冲区... 这样的话很多内容可能都是多余的。 - Ape-inago

0

我越来越频繁地遇到这个问题(当我做UI ajax的事情时),所以我将其打包成一个插件,可以在这里获得。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接