如何解决去抖用户输入的竞争条件?

时间:2016-05-08 21:56:26

标签: javascript

例如,假设某个页面根据去抖用户文本返回搜索结果。

如何解释端点具有高度可变延迟的情况,第二次调用可以在第一次调用之前返回。

E.g。

用户正在键入"书籍和电影" ,其关键帧去抖率为500毫秒

用户在中间略微暂停,因此字符串" books" ,这会触发搜索电话。

用户继续输入并完成,使用"书籍和电影"触发第二个电话。

第二个回复首先返回,根据"书籍和电影" 填充列表。

然后第一个被延迟的电话回来并根据" book" 重新呈现列表。

用户只能看到"图书" 并且感到困惑。

解决此问题的可靠方法是使用按钮手动触发呼叫。我想避免这种情况,所以我增加了去抖,但我想知道是否有更好的方法。

2 个答案:

答案 0 :(得分:3)

我们假设您使用jQuery进行ajax调用。

一种解决方案是使用池系统:基本上是包含ajax请求的数组。 每次发出新请求,您都会中止池中的所有请求。 因此,您确保最后一个请求将是唯一将结束的请求。

以下是池的实现:

jQuery.xhrPool = [];
jQuery.xhrPool.abortAll = function () {
    jQuery(this).each(function (idx, jqXHR) {
        jqXHR.abort();
    });
    jQuery.xhrPool.length = 0;
};

以下是如何将其与GitHub(https://developer.github.com/v3/search/#search-repositories)中的“搜索存储库API”一起使用的示例:

jQuery.xhrPool = [];
jQuery.xhrPool.abortAll = function () {
  jQuery(this).each(function (idx, jqXHR) {
    jqXHR.abort();
  });
  jQuery.xhrPool.length = 0;
};


$(document).ready(function(){
  $("#SearchField").autocomplete({
    source: function( request, response ) {
        // First we abort all other request
        jQuery.xhrPool.abortAll();
      
        $.ajax({
          url: "https://api.github.com/search/repositories",
          method: "get",
          dataType: "jsonp",
          data: {
            q: request.term
          },
          beforeSend: function (jqXHR) {
            // Before sending the request we add it to the pool. 
            jQuery.xhrPool.push(jqXHR);
          },
          success: function(data) {
            var items = new Array();
            for(var i=0;i<data.data.items.length;i++)
            {
              items.push(data.data.items[i].name);
            }
            response(items);
          }
        });
      },
      minLength: 3,
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.css" >
<input type="text" id="SearchField" />

答案 1 :(得分:1)

Javascript同步工作,因此如果您正确编写代码,就不会出现竞争条件。

我猜你正在使用ajax(ajax应该是异步的,不要使用sync,一旦你同步,你就不能回去)来获取查询结果。你可能正在使用这样的代码:

var req=new XMLHttpRequest();


req.onreadystatechange=function(){
    if (req.readyState==4){
        if (req.status==200){
            // Your callback here which shows autocomplete suggestions maybe?
        }
    }
}

坚持req变量。因此,一旦您执行了新请求,您就可以简单地丢弃旧请求,如:

req.onreadystatechange=null;

您还可以abort ajax请求,例如:

req.abort();