管道传输数据以减少分页用 Ajax 调用
服务器端处理过程对您的服务器来说可能非常困难,因为对于发出的每个绘图请求,它都会向服务器发出 Ajax 调用。对于页面浏览量大的网站,您可能最终会用自己的应用程序对自己的服务器进行 DDoSing!
本示例展示了一种通过缓存比每次绘制所需的更多数据来减少向服务器发出的 Ajax 调用次数的技术。具体方法是拦截 Ajax 调用,并通过数据缓存控制将其路由;如果缓存中有数据,则使用缓存中的数据,如果没有,则发出 Ajax 请求。通过将 ajax
选项用作函数,拦截 Ajax 请求。然后,该函数执行逻辑,以决定是否需要另一个 Ajax 调用,或者是否可以使用缓存中的数据。
请记住,这种缓存仅用于分页;对于其他交互(比如排序和搜索),必须清除管道,因为使用服务器端处理时,完整数据集只能在服务器上获取。
名 | 姓 | 职位 | 办公室 | 起始日期 | 薪水 |
---|---|---|---|---|---|
名 | 姓 | 职位 | 办公室 | 起始日期 | 薪水 |
- Javascript
- HTML
- CSS
- Ajax
- 服务器端脚本
- 注释
下面显示的 Javascript 用于初始化本示例中显示的表格
// // DataTables 的流水线功能。用于 DataTables 的 `ajax` 选项// $.fn.dataTable.pipeline = function (opts) { // 配置选项 var conf = $.extend( { pages: 5, // 缓存页数 url: '', // 脚本 URL data: null, // 使用与 DataTables 的 `ajax.data` 工作方式匹配的参数函数或对象 method: 'GET' // Ajax HTTP 方法 }, opts ); // 用于存储缓存的私有变量 var cacheLower = -1; var cacheUpper = null; var cacheLastRequest = null; var cacheLastJson = null; return function (request, drawCallback, settings) { var ajax = false; var requestStart = request.start; var drawStart = request.start; var requestLength = request.length; var requestEnd = requestStart + requestLength; if (settings.clearCache) { // API 请求清除缓存 ajax = true; settings.clearCache = false; } else if ( cacheLower < 0 || requestStart < cacheLower || requestEnd > cacheUpper ) { // 超出缓存数据 - 需要发出请求 ajax = true; } else if ( JSON.stringify(request.order) !== JSON.stringify(cacheLastRequest.order) || JSON.stringify(request.columns) !== JSON.stringify(cacheLastRequest.columns) || JSON.stringify(request.search) !== JSON.stringify(cacheLastRequest.search) ) { // 属性已更改(排序、列、搜索) ajax = true; } // 存储请求,用于下次检查 cacheLastRequest = $.extend(true, {}, request); if (ajax) { // 需要服务器数据 if (requestStart < cacheLower) { requestStart = requestStart - requestLength * (conf.pages - 1); if (requestStart < 0) { requestStart = 0; } } cacheLower = requestStart; cacheUpper = requestStart + requestLength * conf.pages; request.start = requestStart; request.length = requestLength * conf.pages; // 提供与 DataTables 相同的 `data` 选项。 if (typeof conf.data === 'function') { // 作为函数,以数据对象作为 args 执行, // 进行操作。如果返回一个对象,则将其作为 // 提交的数据对象 var d = conf.data(request); if (d) { $.extend(request, d); } } else if ($.isPlainObject(conf.data)) { // 作为对象,给定的数据将扩展默认值 $.extend(request, conf.data); } return $.ajax({ type: conf.method, url: conf.url, data: request, dataType: 'json', cache: false, success: function (json) { cacheLastJson = $.extend(true, {}, json); if (cacheLower != drawStart) { json.data.splice(0, drawStart - cacheLower); } if (requestLength >= -1) { json.data.splice(requestLength, json.data.length); } drawCallback(json); } }); } else { json = $.extend(true, {}, cacheLastJson); json.draw = request.draw; // 更新每次响应的 echo json.data.splice(0, requestStart - cacheLower); json.data.splice(requestLength, json.data.length); drawCallback(json); } }; }; // 注册 API 方法,它会清空流水线数据,强制在下次绘制中进行 Ajax // 获取(即 `table.clearPipeline().draw()`) DataTable.Api.register('clearPipeline()', function () { return this.iterator('table', function (settings) { settings.clearCache = true; }); }); // // DataTables 初始化 // $('#example').DataTable({ ajax: DataTable.pipeline({ url: 'scripts/server_processing.php', pages: 5 // 缓存页数 }), processing: true, serverSide: true });
// // 为数据表进行管道化功能。将其用于数据表的 `ajax` 选项 // DataTable.pipeline = function (opts) { // 配置选项 var conf = Object.assign( { pages: 5, // 需要缓存的页数 url: '', // 脚本 URL data: null, // 含有要发送到服务器的参数的函数或对象 // 匹配 DataTables 中 `ajax.data` 的工作方式 method: 'GET' // Ajax HTTP 方法 }, opts ); // 用于存储缓存的私有变量 var cacheLower = -1; var cacheUpper = null; var cacheLastRequest = null; var cacheLastJson = null; return async function (request, drawCallback, settings) { var ajax = false; var requestStart = request.start; var drawStart = request.start; var requestLength = request.length; var requestEnd = requestStart + requestLength; if (settings.clearCache) { // API 请求清空缓存 ajax = true; settings.clearCache = false; } else if ( cacheLower < 0 || requestStart < cacheLower || requestEnd > cacheUpper ) { // 超出缓存数据 - 需要进行请求 ajax = true; } else if ( JSON.stringify(request.order) !== JSON.stringify(cacheLastRequest.order) || JSON.stringify(request.columns) !== JSON.stringify(cacheLastRequest.columns) || JSON.stringify(request.search) !== JSON.stringify(cacheLastRequest.search) ) { // 属性已更改(排序、列、搜索) ajax = true; } // 存储请求以供下次检查时使用 cacheLastRequest = JSON.parse(JSON.stringify(request)); if (ajax) { // 需要从服务器获取数据 if (requestStart < cacheLower) { requestStart = requestStart - requestLength * (conf.pages - 1); if (requestStart < 0) { requestStart = 0; } } cacheLower = requestStart; cacheUpper = requestStart + requestLength * conf.pages; request.start = requestStart; request.length = requestLength * conf.pages; // 提供与数据表相同的数据选项。 if (typeof conf.data === 'function') { // 作为一个函数,它输出数据对象作为操作的参数。如果返回了一个对象,则它被用作 // 要提交的数据对象 var d = conf.data(request); if (d) { Object.assign(request, d); } } else if (conf.data) { // 作为对象时,给定的数据将扩展默认值 Object.assign(request, conf.data); } // 使用 `fetch` 来发出 Ajax 请求 let response = await fetch( conf.url + '?json=' + JSON.stringify(request), { method: conf.method } ); let json = await response.json(); cacheLastJson = JSON.parse(JSON.stringify(json)); if (cacheLower != drawStart) { json.data.splice(0, drawStart - cacheLower); } if (requestLength >= -1) { json.data.splice(requestLength, json.data.length); } drawCallback(json); } else { json = JSON.parse(JSON.stringify(cacheLastJson)); json.draw = request.draw; // 更新每次响应的回显 json.data.splice(0, requestStart - cacheLower); json.data.splice(requestLength, json.data.length); drawCallback(json); } }; }; // 注册一个 API 方法,它将清空已管道化的数据,强制在下次绘制时进行 Ajax // 提取(即 `table.clearPipeline().draw()`) DataTable.Api.register('clearPipeline()', function () { return this.iterator('table', function (settings) { settings.clearCache = true; }); }); // // 数据表初始化 // $('#example').DataTable({ ajax: DataTable.pipeline({ url: 'scripts/server_processing.php', pages: 5 // 需要缓存的页数 }), processing: true, serverSide: true });
除以上代码外,还加载了以下 Javascript 库文件以用于此示例
下面显示的 HTML 是增强数据表之前未经处理的原始 HTML 表元素
此示例使用了一些额外的 CSS,除了加载自库文件之外(见下文),这些 CSS 用于正确地显示表格。已使用的附加 CSS 如下所示
加载了以下 CSS 库文件以用于此示例,为表格提供样式
此表格通过 Ajax 加载数据。下面显示已加载的最新数据。任何额外数据加载后,此数据都会自动更新。
用于执行此表格服务器端处理的脚本如下。请注意,这只是一个使用 PHP 的示例脚本。服务器端处理脚本可以使用任何语言编写,使用 DataTables 文档中描述的协议。