【问题标题】:How to overwrite setTimeout before it reach the time set?如何在达到设定时间之前覆盖 setTimeout?
【发布时间】:2017-05-25 05:45:11
【问题描述】:

所以我正在使用 jquery 进行自动完成搜索。我必须在执行 ajax 函数之前设置一个延迟,因为我不想每次在文本框上键入时都用调用来敲击我的服务器。这是我的代码:

function searchVendor() {
  setTimeout(searchVendor2, 5000);
}

function searchVendor2() {
  var search = $('#inputVendor').val();
  $.ajax({
    type: 'POST',
    url: '/getVendors',
    data: {search: search},
    dataType: 'json',
    success: function(s) {
      $('#inputVendor').autocomplete({source: s});
    }
  });
}

所以函数searchVendor被执行onkeyup

<input type="text" class="form-control input-sm" id="inputVendor" onkeyup="searchVendor()">

如果我输入 3 个字符(例如 sas),那么函数 searchVendor2 会执行 3 次。 5 秒的延迟有效,但它并没有停止并覆盖之前的 setTimeout

我想要发生的是,如果我在文本框中键入一个字符,它将在 5 秒后执行,但是!如果在 5 秒之前输入了一个新字符,setTimeout 将再次重置为 5 秒。只要用户在文本框上输入,setTimeout 就会重置为 5 秒,并且只有在 5 秒后用户没有再次输入时才会执行。

感谢那些可以提供帮助的人!

【问题讨论】:

  • 您可以提供minLength 选项,以便仅在用户输入最少字符后进行搜索。例如:minLength: 3
  • 我不确定我能不能这么说,但这不会破坏自动完成的目的吗?我认为最好使用自动完成这样的最小长度提供的功能。

标签: javascript jquery settimeout


【解决方案1】:

首先,您需要将超时 id 保存在全局变量中,或者保存在稍后再次调用函数时可以访问的变量中。

现在,无论何时调用您的函数,首先您要清除该超时(如果存在)。因此,您可以在每次调用该函数时清除任何预先存在的超时并设置一个新的超时。

var myTimeout;

function searchVendor() {
  clearTimeout(myTimeout);
  myTimeout = setTimeout(searchVendor2, 5000);
}

function searchVendor2() {
  var search = $('#inputVendor').val();
  $.ajax({
    type: 'POST',
    url: '/getVendors',
    data: {search: search},
    dataType: 'json',
    success: function(s) {
      $('#inputVendor').autocomplete({source: s});
    }
  });
}

【讨论】:

  • 因为 first 将未定义 if (myTimeout) {clearTimeout(myTimeout)}
  • @NightKn8 不值得把它放在if 检查中。 clearTimeout() 忽略 undefined 和其他不存在的计时器 ID。并且没有显着的性能成本。
  • @SethHolladay 是的,你是对的,Link。这在我上面的zzzzBov 链接中提到的边缘情况 的情况下很有用,但在这种情况下不需要。
【解决方案2】:

涉及setTimeout() 的其他答案很简单并且会起作用,但这是我建议使用实用程序库的少数几次之一,因为它们可以以一种用户可以注意到的方式更进一步。

避免重新发明轮子也很重要。在这种情况下,您需要一个 debouncethrottle 函数来限制处理程序在给定时间跨度内执行的次数。好的库还接受选项来调整您的处理程序何时运行,这可能会影响您的应用程序的响应能力。

Read more about debouncing and throttling.

对于您的用例,我会推荐 Lodash 的 _.throttle(),同时将 leadingtrailing 选项设置为 true。这将确保长文本条目仍将获得一些中间结果,同时也尽可能快地获得结果(不必在第一次等待计时器)并且仍然保证最终击键将触发新结果,这并非所有去抖动设置都可以。

const handler = (evt) => {
    console.log('I will talk to the server.');
};

const throttled = _.throttle(handler, 500, {
    leading  : true,
    trailing : true
});

然后将节流函数注册为事件监听器。

<input type="text" class="form-control input-sm" id="inputVendor" onkeyup="throttled()">

【讨论】:

  • 哇!谢谢(你的)信息。我认为我的代码运行起来就像去抖动。
【解决方案3】:

当你想停止超时时,你必须清除它。而不是仅仅这样做:

var timeoutId;
function searchVendor() {
  timeoutId = setTimeout(searchVendor2, 5000);
}

你应该添加clearTimeout(timeoutId);,像这样:

var timeoutId;
function searchVendor() {
  clearTimeout(timeoutId);
  timeoutId = setTimeout(searchVendor2, 5000);
}

【讨论】:

    【解决方案4】:

    您可以使用autocomplete 中的minLength,这样就不会在用户开始输入时立即调用API。

    Here is the reference from autocomplete

    minLength:执行搜索前用户必须输入的最少字符数

    $( "#inputVendor" ).autocomplete({
      minLength: 3
    });
    

    如果您希望每次按键都像其他答案所建议的那样,您可以使用clearTimeout 删除旧的超时。

    var timeout;
    
    function searchVendor() {
       clearTimeout(timeout);
       timeout = setTimeout(searchVendor2, 5000);
    }
    

    【讨论】:

      【解决方案5】:

      setTimeoutsetInterval 函数可以使用 clearTimeoutclearInterval 函数停止,传递第一个函数生成的唯一标识符。例如,这里有一个小代码可以帮助您理解这一点:

      var delay;
      
      document.addEventListener("mousemove", function () {
          callSetTimeout();
      });
      
      function callSetTimeout () {
      
          if (!isNaN(delay)) { clearTimeout(delay); }
      
          delay = setTimeout(function () {
              console.log("do something");
          }, 5000);
      
      }
      

      【讨论】:

        【解决方案6】:

        我更改了超时,但我检查了间隔

        var goal={
            cb: cb
        ,   timeout: (+new Date())+60000 //one minute from now
        ,   setInterval(function(){
                if((+new Date())>goal.timeout){cb();}
                })
            };
        

        现在我想增加、减少或重置超时时间?

        goal.timeout-=1000;
        goal.timeout+=1000;
        goal.timeout=60000;
        

        【讨论】:

          猜你喜欢
          • 2021-09-29
          • 1970-01-01
          • 2016-04-06
          • 2015-02-15
          • 2016-04-07
          • 1970-01-01
          • 2016-08-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多