【问题标题】:JQuery ajax .abort()jQuery ajax .abort()
【发布时间】:2015-10-01 13:14:08
【问题描述】:
  1. 用户点击搜索框
  2. 用户输入姓氏
  3. 如果 texbox 长度超过 2 个字符,则 ajax webservice 是 叫

我遇到的问题是具有数千条记录的慢速数据库...

我可以输入“mcm”并等待,它会在 3 秒内返回 40 个结果。 我可以继续输入“mcmil”,它会在 1 秒内返回 11 个结果。

问题是,如果我从头开始一次输入“mcmil”,我可以明显看到前 11 个结果,然后随着“mcm”和“mcmi”的结果被加载,结果会跳跃,大概是因为它们速度较慢.

当 .keyup 触发时,我需要一种方法来检测当前是否正在发出 .ajax 请求并在发出新请求之前取消它。

$('#employeesearchbox').keyup(function () {

    if ($("#employeesearchbox").val().length > 2) {

        $.ajax({
            type: 'POST',
            url: './webservices/Contacts.asmx/ContactsDirectorySearch',
            data: JSON.stringify({ Surname: $("#employeesearchbox").val() }),
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function (msg) {
                var employees = msg.d;
                $.each(employees, function (index, employee) {
                    $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
                });
            },
            error: function (xhr, ajaxOptions, thrownError) {
                console.error("The error was: " + xhr.responseText);
            }
        });

    }

});

我看过这个帖子:abort-ajax-requests-using-jquery

它在 .ajax 之后直接取消请求,因为我可能想在下一次按键时进行测试,当我添加此代码时,我得到“对象未定义”错误 - 因为对象不存在!

请帮忙

谢谢

var xhr = $.ajax({
 ...
});

//kill the request
xhr.abort()

【问题讨论】:

  • 可能会在触发请求之前添加一点延迟?
  • 可能,但我宁愿在创建新请求之前清除先前的请求。有些搜索可能需要长达 5-6 秒,所以我不想添加延迟来覆盖它,因为系统可能会显得无响应和令人沮丧!
  • 您可能想要查看预先输入 (twitter.github.io/typeahead.js/examples)。它会为您处理计时请求并将结果显示给用户。它还限制了发送的请求数量,这样您的数据库就不会被太频繁地访问。
  • 问题是,在您触发 ajax 请求后,服务器将继续运行。我认为 abort() 所做的就是停止触发回调。我有一个对 1​​00,000 多条记录进行 i-search 的查找,但在输入 4 个字母之前我不会触发请求。我没有注意到这些比赛条件。这是你可以考虑的吗? (编辑 OK 我看到你等待两个字符,等待 4 会大大减少响应量)
  • 您的var xhr = $.ajax({ 是在keyup 范围内还是在外部?如果您的变量声明在范围内,则无法取消它,因为它不存在。

标签: jquery ajax


【解决方案1】:

扩展我的评论 -

我正在考虑将您的 ajax 放在可能半秒的 setTimeout 中,每次新按键都会清除该时间。大多数人会比这更快地打字。另请查看此问题的答案 - Average Inter-Keypress time when typing 并可能查看已接受答案的 cmets 中的链接

例如-

var delaySearch;
$('#employeesearchbox').keyup(function () {
  if ($("#employeesearchbox").val().length > 2) {
    clearTimeout(delaySearch);
    delaySearch = setTimeout(function() {
      $.ajax({
        type: 'POST',
        url: './webservices/Contacts.asmx/ContactsDirectorySearch',
        data: JSON.stringify({ Surname: $("#employeesearchbox").val() }),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function (msg) {
          var employees = msg.d;
          $.each(employees, function (index, employee) {
            $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
          });
        },
        error: function (xhr, ajaxOptions, thrownError) {
          console.error("The error was: " + xhr.responseText);
        }
      });
    }, 500);
  }
});

我已将超时设置为 500 毫秒,但您可能希望延长一点,具体取决于您的数据库性能和目标受众。

【讨论】:

  • 嗨,John,感谢您提供的示例,我有一些额外的代码我没有发布,以使我的示例保持简短和重点。我实际上已经将我的 db 调用与逻辑分开了,但最终这里有不止一种方法可以给猫剥皮。看到你把完整的 ajax 部分放在 setTimeOut 中很有趣 :) 我用这个 timer = setTimeout(searchDatabase, 500);然后清除 .keyup 中的计时器
【解决方案2】:

沿着这些思路呢?为发送的每个请求创建一个 id,将其传递给服务器并从服务器发回。仅当请求不是太旧时才更新文档。

我仍然认为您应该考虑对这些请求进行去抖动基本上,不要在 300 毫秒之前发送请求,直到它们完成输入或其他操作。

    var requestid = 0;
    $('#employeesearchbox').keyup(function () {

        if ($("#employeesearchbox").val().length > 2) {
            requestid++;
            $.ajax({
                type: 'POST',
                url: './webservices/Contacts.asmx/ContactsDirectorySearch',
                data: JSON.stringify({ Surname: $("#employeesearchbox").val(), requestid: requestid }),
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                error: function (xhr, ajaxOptions, thrownError) {
                    console.error("The error was: " + xhr.responseText);
                }
            }).done(function(msg){
                if(msg.requestid >= requestid){
                    var employees = msg.d;
                    $.each(employees, function (index, employee) {
                        $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
                    });  
                }
            });

        }

    });

【讨论】:

  • 你觉得我的回答有用吗?
  • 嗨@bingo,是的,它很有用,我添加了一个 setTimeout 函数来充当按键和调用数据库之间的缓冲区,因此现在用户键入时会有半秒的延迟。感谢 timer = setTimeout(searchDatabase, 500);
  • 太棒了!你会赞成我的评论吗?试着在这里升级一点! :) 我刚刚对罗伯茨的评论投了赞成票,这实际上比我的整体要好。
【解决方案3】:

感谢@robert,这是工作代码。

xhr 被声明为 null outsite .keyup 范围 按键后,我可以检查它是否不等于 null 并使用 .abort() 取消它

var xhr = null;

$('#employeesearchbox').keyup(function () {

    if ($("#employeesearchbox").val().length > 2) {

        if (xhr == null) {
            console.error("null");
        } else {
            //kill the request
            xhr.abort()
        }

        xhr = $.ajax({
            type: 'POST',
            url: './webservices/Contacts.asmx/ContactsDirectorySearch',
            data: JSON.stringify({ Surname: $("#employeesearchbox").val() }),
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function (msg) {
                var employees = msg.d;
                $.each(employees, function (index, employee) {
                    $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
                });
            },
            error: function (xhr, ajaxOptions, thrownError) {
                console.error("The error was: " + xhr.responseText);
            }
        });

    }

});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 2021-08-30
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    相关资源
    最近更新 更多