【问题标题】:Speed up a web service for auto complete and avoid too many method calls为自动完成加速 Web 服务并避免过多的方法调用
【发布时间】:2010-06-11 19:36:43
【问题描述】:

所以我已经让我的 jquery 自动完成“工作”,但它有点烦躁,因为我每次触发 keydown() 时都会调用 web 服务方法,所以我有很多方法挂起,有时让“自动”工作我必须输入它并退格一点,因为我假设它的返回值有点慢。我已将查询结果限制为 8 以最小化时间。我能做些什么来让它变得更活泼一点吗?如果我不让它更敏感一点,这东西似乎几乎没用。

javascript

$("#clientAutoNames").keydown(function () {
        $.ajax({
            type: "POST",
            url: "WebService.asmx/LoadData",
            data: "{'input':" + JSON.stringify($("#clientAutoNames").val()) + "}",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (data) {
                if (data.d != null) {
                    var serviceScript = data.d;
                }
                $("#autoNames").html(serviceScript);
                $('#clientAutoNames').autocomplete({
                    minLength: 2,
                    source: autoNames,
                    delay: 100,
                    focus: function (event, ui) {
                        $('#project').val(ui.item.label);
                        return false;
                    },
                    select: function (event, ui) {
                        $('#clientAutoNames').val(ui.item.label);
                        $('#projectid').val(ui.item.value);
                        $('#project-description').html(ui.item.desc);
                        pkey = $('#project-id').val;
                        return false;
                    }
                })
            .data("autocomplete")._renderItem = function (ul, item) {
                return $("<li></li>")
                    .data("item.autocomplete", item)
                    .append("<a>" + item.label + "<br>" + item.desc + "</a>")
                    .appendTo(ul);
            }
            }
        });
    });

WebService.asmx

<WebMethod()> _
Public Function LoadData(ByVal input As String) As String
    Dim result As String = "<script>var autoNames = ["
    Dim sqlOut As Data.SqlClient.SqlDataReader
    Dim connstring As String = *Datasource*

    Dim strSql As String = "SELECT TOP 2 * FROM v_Clients WHERE (SearchName Like '" + input + "%') ORDER BY SearchName"
    Dim cnn As Data.SqlClient.SqlConnection = New Data.SqlClient.SqlConnection(connstring)
    Dim cmd As Data.SqlClient.SqlCommand = New Data.SqlClient.SqlCommand(strSql, cnn)
    cnn.Open()

    sqlOut = cmd.ExecuteReader()
    Dim c As Integer = 0
    While sqlOut.Read()

        result = result + "{"
        result = result + "value: '" + sqlOut("ContactID").ToString() + "',"
        result = result + "label: '" + sqlOut("SearchName").ToString() + "',"
        'result = result + "desc: '" + title + " from " + company + "',"
        result = result + "},"

    End While
    result = result + "];</script>"
    sqlOut.Close()
    cnn.Close()

    Return result
End Function

我确定我只是在解决这个问题,或者没有更好地平衡通话或其他事情。

非常感谢!

【问题讨论】:

  • “延迟:100”是指100ms吗?
  • 是的,我不认为我在阅读 API 时会像您那样阅读它。出于某种原因,我认为延迟是要等多久才能显示建议 - 我认为这只会让我的最终用户变得更慢
  • 事实证明我对延迟的使用方式是正确的。我用萤火虫把它拉起来,它仍然很快被调用,我想知道我是否应该将它更改为由函数调用的 ajax 调用,以便我可以更好地控制何时获得结果,以便我可以创建延迟。

标签: asp.net javascript jquery sql-server


【解决方案1】:

首先,您必须调整查询。你没有使用参数化查询,所以你只是在乞求SQL injection 攻击。

同样,您必须先解决这个问题!

完成此操作后,请使用“延迟”值。我假设这是在将查询发送到服务器之前在按键之间等待的时间?您希望它等待您的用户暂停输入,然后发送请求,以避免因无关调用而使您的服务器过载。

您还应该使用 try..catch..finally 并在完成后丢弃您的连接。

顺便说一句,如果您的查询表现不佳,请尝试在该列上添加索引。如果你没有索引,'Like' 语句会很糟糕......

【讨论】:

  • 感谢您指出这一点。我听说过sql注入,你能建议我如何参数化查询吗?我是 ASP 的新手。我也没有过多担心这个问题,因为这是一个小型的内部 CRM,但是,当你指出它有多严重时,我会解决它。
  • 就此而言,服务器代码缺乏错误处理。它应该在大部分代码周围有一个 try 块,并带有一个 catch 块来记录错误并返回一些安全的东西,比如一个空字符串。它还应确保处理所有一次性物品,最好使用using 语句。除了参数化,这些是稳定服务器的基本要求。
  • 我可能还应该提到应该使用 String.Format 创建返回值,而不是串联。
  • 我在别处提到过——我将结果注入到页面中有点生硬——如果您熟悉 jquery 的自动完成工作原理,您会建议我更改将可能字符串的变量发送到页面的方式吗?这是我能想到的最好的可行方式,但又感觉有点老套。
  • @jphenow:我可能会稍微调整一下; JSON.strinify({ input: $("#clientAutoNames").val() }) 会更干净。
【解决方案2】:

在执行任何其他操作之前,您应该首先考虑缓存从数据库返回的结果。这将限制您对数据库执行的查询数量。如果您通过单个 Web 服务器运行这些查询,请考虑使用 System.Web.Cache 来缓存结果。

关于如何优化的任何其他建议将取决于您提供的信息之外的更多信息 - 即您是否在网络场中运行、您有多少数据库服务器、您的性能要求是什么等。

我还建议您阅读SQL injection 上的维基百科条目。一世 相信 ASP.NET 默认会阻止包含单引号的请求,但您仍应修复您的代码。

【讨论】:

  • 您看到我当前如何将查询到的内容添加到 default.aspx 页面中的 div 选择器中了吗?将其缓存在服务上只是使其“查询”服务还是建议我以更好的方式将其添加到页面中?
  • 我会忽略页面方面,直到您在服务器端实现中获得正确的延迟。在页面级别缓存它肯定会有所帮助(即当用户按下退格键时),但您希望服务器端正确。您在 SearchName 列上有索引吗?
【解决方案3】:

对“snappier”的一些建议

根据要求,您可能会在客户端构建预防措施,以防止过多的服务器调用和隐含的调用延迟。例如,

  • 自动完成只能在至少输入 3 个字符后启动;否则结果太宽泛而无足轻重;
  • 随着用户键入的内容越来越多,列表应该不断变小,因此在客户端缓存原始列表并在用户继续键入更多字符时对其进行过滤。如果用户退格超过原始结果集,则从服务器获取一个新结果集并对其执行相同操作。
  • 使用客户端计时器以不超过 2 或 3 秒的间隔发出呼叫。 keydown 会检测到文本框中的变化,当你的计时器触发时,它会查看该标志以确定它是否应该再次提取数据

诚然,其中一些可能不会导致活泼,但这取决于您如何使用它们。例如,定时器延迟在逻辑上对速度没有贡献,但是再次比较服务器被呼叫淹没并且响应更慢的替代方案,它可能会。里程总是随着这种类型的优化而变化,并且您经常以服务器工作换取客户端速度。

【讨论】:

  • 我可以处理顶级的 - 最后一个让我抓到了。我正在努力解决这个问题,而我目前将返回值发送回页面的方式使得很难“添加”到列表中——更像是重写列表。你对我如何冷发送一个可以操纵的列表有什么想法吗?
  • 如果你收到一个 JSON 数据响应,那么它已经是一个 JavaScript 结构(哈希或数组),所以只需在你的 JS 代码var originalData = whateverJQueryReturned; 中保留对它的引用。然后编写一个函数来迭代该散列或数组,以编写一个新的数据结构,其值仅限于文本框中当前的值 - 您将显示该新子集。您的函数将不断地针对该原始列表运行,每次都通过在用户键入时将其切割成一个新列表来执行相同的操作。
  • 我不会担心在客户端合并或添加列表。替换听起来不错,如果需要,您可以采取更多优化措施。
【解决方案4】:

您可以在 Web 服务上使用数据缓存并将一些数据保存在服务器上,而不是在后续调用时转到数据库。

如果v_Clients中的数据没有太多记录,你可以把整个东西放在缓存中,用LINQ查询。

http://msdn.microsoft.com/en-us/library/system.web.httpcontext.cache.aspx

【讨论】:

  • 我会缓存更多,但有数百个条目并且还在增长 - 这是一个内部 CRM
【解决方案5】:

除非绝对必要,否则您希望避免在每次击键时调用服务器..

它是在查询一个庞大的数据集吗?如果没有,您可以在页面加载时将整个数据集缓存在局部变量中。

如果数据集很大,您可以考虑智能缓存,即缓存大部分时间使用的数据,而不是按需获取不太常见的场景。

还可以防止前几个字符的自动完成。即至少需要 4 人才能拨打电话。

您必须在这里使用您的判断,但在调整时进行测量和观察,以便对性能/数据可靠性等有一个很好的了解。

【讨论】:

    猜你喜欢
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-15
    相关资源
    最近更新 更多