加速 Ajax 成功的 DOM 操作

Speeding up Ajax success DOM manipulation

本文关键字:DOM 操作 成功 Ajax 加速      更新时间:2023-09-26

我在我的页面上使用了 AJAX 调用,该调用返回表行,并在成功后将它们添加到页面中的表中。以下是当前使用的代码:

function GetDPRecords(Perso) {
        //alert(Perso);
        $Records = $('#DPRecords');
        //alert($PersoFileName.val()+" | "+$ProcFromDate.val()+" | "+$ProcToDate.val());
        $.ajax({
            type: "GET",
            url: "SelectDPRecords.jsp",
            data: $('form#Search_Form').serialize() + "&Personalized=" + Perso,
            beforeSend: function () {
                $Records.find("tr:gt(0)").remove();
                $("<tr><td colspan='4'><h3 style='margin: 4px 10px'> Loading... </h3></td></tr>").hide().appendTo($Records).show(400);
            },
            success: function (data) {
                $Records.find("tr:gt(0)").remove();
                $(data).hide().appendTo($Records).show(400);
            }
        });
    }

问题是我有时期望返回大量行(1,000-5,000)。我用返回的 4,000 行数据进行了测试运行,它导致浏览器在大约 20 秒内无响应。

有什么方法可以优化代码并减少加载时间吗?

一种可能的解决方案是使用分页系统:不是返回 1,000-5,000 行,而是将结果分成每页 50 个结果的页面,并且一次只返回一页。然后,您将为用户提供按钮以在表格的顶部/底部加载其他页面。

有关我正在谈论的示例,请参阅 http://luis-almeida.github.io/jPages/defaults.html。它使用图片而不是行,但它是相同的基本概念。

只是为了添加@aj_r的建议 如果您不想再次访问服务器来检索下一个范围的数据,则可以将结果存储到 javascript 变量(JSON 对象数组)中,然后在本地使用它进行分页。

我最近在jqGrid中使用巨大的数据网格时遇到了同样的问题,并且我已经能够找到一个棘手的解决方案,结果证明它运行良好。

问题是你不能一次渲染所有这些数据 - 这太多了,特别是考虑到 DOM 操作有多慢。所以你需要某种队列。您可以将这些数据拆分为块,并使用setTimeout()setInterval()按顺序呈现它们,但这些块在性能方面也没有很好的声誉。

我最终使用了reuestAnimationFrame,并将我的大量数据分成几部分,并在动画帧可用时渲染它们。所以你需要从 polyfill 开始,以确保你要做的事情真的有效,我正在使用 Paul Irish 的一个很棒的:

这里有一个可怕的jsFiddle:http://jsfiddle.net/cjw5eota/1/

这是JS:

var dataRows = 5000; // enter ammount of returned rows
var chunkSize = 200; // define single chunk size, optimize for best performance bu trying different values, if your DOM manipulation is heavy use less, if its lightweight you can use more, use 1 to see in slowmo how it works
// We are simulating big returned object here
var data = {}
for (var i = 0; i < dataRows; i++) {
    data[i] = {
        'id': i,
        'name': 'I am data for row ' + i
    };
}
// shim layer with setTimeout fallback
window.requestAnimFrame = (function () {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
        window.setTimeout(callback, 1000 / 60);
    };
})();
function renderRecords(data) {
    var dataLength = Object.keys(data).length;
    var i = 0;
    function renderInQueue() {
        console.time('Rendering in queue');
        for (t = 0; t < chunkSize; t++) {
            if (i < dataLength) {
                var row = '<tr><td>' + data[i].id +
                    '</td><td>' + data[i].name + '</td></tr>'
                $('table').append(row);
            }
            i++;
        }
        if (i < dataLength) {
            requestAnimationFrame(renderInQueue);
        } else {
            console.log('Done rendering');
            console.timeEnd('Rendering in queue');
        }
    }
    renderInQueue();
}
// run the script of rendering
renderRecords(data);

我提供了一个简单的性能基准测试,供您在控制台中查看整个渲染过程需要多少时间。使用chunkSize看看它是如何变化的,并尝试找到最适合您需求的值,即在不给浏览器带来沉重负担的情况下为您提供体面的渲染时间。

您尝试一次渲染的次数越多,渲染速度就越快,但处理每次渲染迭代需要更多的资源。