使用管線化數據減少分頁的 Ajax 呼叫
伺服器端處理對您的伺服器來說可能相當繁重,因為它會針對每個繪製請求向伺服器發出 Ajax 呼叫。在具有大量頁面瀏覽量的網站上,您可能會因為自己的應用程式而導致伺服器遭受 DDoS 攻擊!
此範例展示一種技術,透過快取每個繪製所需以外的更多數據,來減少發送到伺服器的 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: '', // 腳本網址 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') { // 作為函式,它會使用數據物件作為 arg 執行 // 以進行操作。如果傳回物件,則會將其用作要提交的 // 數據物件 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; // 更新每個回應的回顯 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 });
// // DataTables 的管線化函式。用於 DataTables 的 `ajax` 選項 // DataTable.pipeline = function (opts) { // 配置選項 var conf = Object.assign( { pages: 5, // 要快取的頁數 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; // 提供與 DataTables 相同的 `data` 選項。 if (typeof conf.data === 'function') { // 作為函式,它會使用數據物件作為 arg 執行 // 以進行操作。如果傳回物件,則會將其用作要提交的 // 數據物件 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; }); }); // // DataTables 初始化 // $('#example').DataTable({ ajax: DataTable.pipeline({ url: 'scripts/server_processing.php', pages: 5 // 要快取的頁數 }), processing: true, serverSide: true });
除了上述程式碼外,還載入了以下 Javascript 函式庫檔案以供此範例中使用
以下顯示的 HTML 是原始 HTML 表格元素,在 DataTables 增強之前
此範例使用了程式庫檔案(如下)載入以外的一些額外 CSS,以便正確顯示表格。使用的額外 CSS 如下所示
以下 CSS 函式庫檔案已載入供此範例使用,以提供表格的樣式
此表格透過 Ajax 載入數據。下方顯示已載入的最新數據。當載入任何其他數據時,此數據將自動更新。
下方顯示用於執行此表格伺服器端處理的腳本。請注意,這只是一個使用 PHP 的範例腳本。伺服器端處理腳本可以使用任何語言編寫,使用 DataTables 文件中描述的協定。