jquery ajax:按正确顺序处理typeahead事件?

时间:2015-10-12 00:06:38

标签: javascript jquery ajax typeahead

我正在使用html + jquery和java rest-service后端进行webapp。 我有一个带有预先输入建议的文本字段,因此用户在字段中输入的每个字符都是如此 将触发服务器往返并更新预先建议列表。

代码的基本部分:

    var showTypeaheadSuggestions = function(data) {
        // update ui-element ...
    }

    var displayFailure = function() {
        // update ui-element ...
    }

    var searchText = $("#searchText");
    var searchTextKeyup = function() {
        var txt = searchText.val();
        $.ajax({
            url : typeaheadUrl(txt),
            type : 'GET',
            dataType : 'json',
        }).done(showTypeaheadSuggestions).fail(displayFailure);
    }
    searchText.on('keyup', searchTextKeyup);

它基本上起作用了。 但我正在考虑如果你打字会发生什么,例如,2个字母“ab”(这将首先触发“a”的请求,然后是“ab”的请求)...

然后,如果“a”响应需要更长的时间来处理,并且响应之后到达会发生什么? 我是否需要在我的代码中检测,以丢弃“a”响应?

http://api.jquery.com/jquery.ajax/中它确实说:

  

承诺回调 - .done(),. fail(),. aways()和.then() - 是   按照他们注册的顺序调用。

这究竟是什么意思? 我希望这意味着$ .ajax()会自动处理上述情况。

但是当我做一个小测试时(在服务器端我只注入2秒的睡眠延迟,只有当搜索字符串完全是“a”时), 事实证明它的行为与我预期的一样。

预先输入列表将首先使用“ab”响应进行更新,然后在“a”响应时进行更新 到达时,它也会更新,因此预先输入列表会得到错误的建议。

正确处理此问题的既定方法是什么?

4 个答案:

答案 0 :(得分:1)

我解决此问题的方法之一是每次调用它时分配一个ID,并将其作为ID传递给服务器端。当您的服务器完成处理后,它会将结果与其ID一起发回。

然后,每次客户端代码运行时,ID都会递增。例如:

var callback_id = 0;

var searchText = $("#searchText");
var searchTextKeyup = function() {
    callback_id ++;
    var txt = searchText.val();
    $.ajax({
        url : typeaheadUrl(txt),
        data : callback_id,
        type : 'GET',
        dataType : 'json',
    }).done(showTypeaheadSuggestions).fail(displayFailure);
}
searchText.on('keyup', searchTextKeyup);

然后,当您收到回复时,检查id是否为当前。如果用户一次触发两个事件,您的ajax事件将被触发两次,一次使用callback_id = 0,另一次使用callback_id = 1

您必须做的最后一件事是if语句只更新TypeaheadSuggestions,如果callback_id是最新的{1}},则比较从服务器响应发回的ID。

答案 1 :(得分:1)

您必须将新输入文字与您发送的文字进行比较,如果是用户想要查找的内容 - 您将显示它,否则不会对回复做任何事情。

例如:

var searchText = $("input").val()
$.ajax({
        ....
        data: {searchText : searchText}
        success: funtion(){
        if($("input").val()==searchText){
           //SHOW RESULTS
        }
     }
})

答案 2 :(得分:1)

如果您想保留服务器端代码而不进行更改,还有另一种方法。实际上,您可以将返回函数包装在类中并为每个请求创建实例,然后将最新实例存储在全局范围变量中,并检查调用方法的所有者是否与最新实例匹配:

var lastRequest;
var searchText = $("#searchText");

function requestClass()
{
    var that = this;

    this.showTypeaheadSuggestions = function(data) {
        //Update ui-element
        if (lastRequest == that)
            console.log('suggestions retrieved: ' + data);
        else
            console.log('this response (' + data + ') is ignored');
    };

    this.displayFailure = function() {
        //Update ui-element
        console.log('failure');
    };
}

var searchTextKeyup = function() {
    var request = new requestClass();
    lastRequest = request;

    var txt = searchText.val();
    $.ajax({
        url : typeaheadUrl(txt),
        type : 'GET',
        dataType : 'json',
    }).done(request.showTypeaheadSuggestions).fail(request.displayFailure);
}

searchText.on('keyup', searchTextKeyup);

我已经使用您在问题中提出的小测试对此进行了测试(当搜索字符串与' a'字符匹配时添加2秒延迟),结果如下:

suggestions retrieved: ab
this response (a) is ignored

答案 3 :(得分:1)

Promises接口立即向您返回“Promise对象”,以便您可以使用不同的语法进行回调。

而不是:

Array

您可以使用:

asyncCall(callback);

你可以链接这些:

asyncCall()
  .then(callback);

回调将按照您注册的顺序执行 - authorizeAccount() .then(getNames) .then(processNames); 将等待processNames先解决。

“正确”处理这种“已建立”的方法可能是添加一些客户端去抖动,以便只有整个请求('查询'而不是'q','qu''que'...)是在您输入单词时处理: 如果需要很长时间才能返回,则http://underscorejs.org/#debounce超时会使响应失效。