如何停止 DataTables 实例已启动的所有当前正在进行的 Ajax 查询?
Posted
技术标签:
【中文标题】如何停止 DataTables 实例已启动的所有当前正在进行的 Ajax 查询?【英文标题】:How can I stop all the currently ongoing Ajax queries that DataTables instance have started? 【发布时间】:2014-12-19 08:21:27 【问题描述】:简要说明
将测试服务器重置为已知状态会导致我的测试失败,因为在重置服务器时 DataTables 实例正在启动 Ajax 请求。我想通过在服务器重置之前停止 DataTables 请求来防止这种情况发生。
详细说明
我有一个在某些页面上使用 DataTables 的应用程序。这些数据表都执行服务器端查询来填充它们的表。
当我执行系统测试时,有时会发生竞争情况:
测试运行器启动测试服务器。
测试运行程序在测试浏览器中加载一个页面,其中某处有一个 DataTable 实例。
测试运行程序运行测试,该测试执行检查并结束。
测试运行程序将测试服务器重置为已知状态以进行下一次测试。
页面上显示一条警报,指出 DataTables 遇到了 Ajax 错误。警报说:
DataTables 警告:table id=[some id] - Ajax 错误。有关此错误的更多信息,请参阅http://datatables.net/tn/7
-
我的测试系统没有收到警报,即使测试实际上是成功的,它也会感到困惑并记录失败。 (或者在某些情况下,它会崩溃。)
我知道这是因为服务器突然中断了一个 Ajax 请求。我正在寻找的是一种防止警报出现的方法。我想在服务器重置之前停止所有正在进行的 DataTables 请求。
解决方案已被拒绝
告诉 DataTables 实例不要使用警报:如果 DataTables 实例遇到与重置测试服务器无关的问题,我希望我的测试严重失败。
修改测试服务器:我更喜欢让服务器保持简单,而不是担心那里可能无法响应的请求。
等待客户端所有请求结束:这会大大减慢测试速度,尤其是当这种等待重复进行数十次测试时。
将测试浏览器定向到一个新页面,其中没有 DataTables,因为这会中断当前请求:这又会损害测试性能。
【问题讨论】:
【参考方案1】:解决方案
在测试完成所有检查后,让驱动浏览器的软件在浏览器中执行以下代码。 (这将在测试后运行某种“拆除”代码。)
if (typeof $ !== "undefined" && $.fn.dataTable)
var all_settings = $($.fn.dataTable.tables()).DataTable().settings();
for (var i = 0, settings; (settings = all_settings[i]); ++i)
if (settings.jqXHR)
settings.jqXHR.abort();
说明
即使在未加载 jQuery 或未加载 DataTables 的页面上执行,代码也可以正常工作。因此它首先检查它们是否已加载,如果未加载则不执行任何操作。然后它获取所有 DataTable 实例的设置对象。在每个设置对象中,它检查jqXHR
的存在,当发出Ajax 请求时,它会填充一个jQuery jqXHR
对象。它将在其上调用abort()
方法,从而中止请求。
上面的代码适用于 DataTables 1.10,无论表使用 1.10 API 还是 1.9 API。但是请注意,jqXHR
字段并不是公共 API 的正式组成部分。同时,其中一位开发人员在DataTables forum 上没有任何警告地谈论它,所以这可能不是私有 API 中最危险的部分。完全依赖公共 API 的解决方案会更加麻烦,因为必须修改所有 DataTable 实例以跟踪标记 Ajax 事务开始和结束的事件或具有自定义 Ajax 处理程序等。这将有不仅适用于正在测试的项目的代码,还适用于提供恰好使用 DataTables 的 html 小部件的任何第 3 方库。
请注意,上面的代码不会阻止 DataTables 实例发起new 请求。但这不是我所关心的。
【讨论】:
【参考方案2】:我认为更好的方法是在 DataTables 中使用 preXhr.dt 事件。
$('.datatable').
on('preXhr.dt', function ( e, settings, data )
if (settings.jqXHR) settings.jqXHR.abort();
).DataTables();
【讨论】:
我不这么认为。我看到preXhr
发出“之前到 DataTables 向服务器发出 Ajax 请求以获取数据”。 (强调原文。)如果我使用您在最初设置表时显示的代码,那么我将预先中止所有 Ajax 请求,并且我的测试将失败,因为我的表不工作.如果我在完成测试后添加监听器,那么问题是我只是中止了 future 请求。有一些在测试期间生成的请求在测试结束时仍然没有解决。我需要中止 这些 以避免我报告的错误。
@Louis 实际上上面的代码可以工作。如果另一个已经在运行,它只会中止 ajax 请求。因此,如果 ajax 请求为页面加载触发一次,它不会“阻止”它工作。如果说连续发出 5 个 ajax 请求,则前 4 个被取消(使用.abort()
),第 5 个运行并返回数据。我已经在一个应用程序中尝试过了,并使用浏览器控制台的网络选项卡对其进行了监控。
@Andy 为了让事情正常工作,不应该中止 4 个初始 Ajax 请求 --- 以便表实际上是可测试的 --- 但应该中止第 5 个,以便任何测试结束后运行的尾随 Ajax 请求会从客户端中止,而不是因为服务器在重置时突然关闭连接而出错。您描述了与这种期望行为完全相反的情况。
当然应该中止最初的那些。早于最新请求开始的任何内容基本上都是无用的,因为它生成的数据与搜索条件不匹配!我的应用程序通过附加到表单的.keyup
事件发送请求。如果用户键入“abcde”,您不希望发送“a”、“ab”、“abc”、“abcd”的 4 个 ajax 请求 - 因为这些不会为用户产生正确的结果。任何比最新请求更早的东西都应该被中止。我目前正在开发一个应用程序。
对于服务器端和过滤这就像一个魅力。很好的解决方案,不像标记的答案那么老套。但我想在 if 中看到花括号 - 像这样: if (settings.jqXHR) settings.jqXHR.abort(); 以上是关于如何停止 DataTables 实例已启动的所有当前正在进行的 Ajax 查询?的主要内容,如果未能解决你的问题,请参考以下文章