如何优化将大量元素动态添加到网页中

Posted

技术标签:

【中文标题】如何优化将大量元素动态添加到网页中【英文标题】:How to optimize adding numerous elements dynamically into web page 【发布时间】:2019-06-03 18:28:42 【问题描述】:

我需要从我的数据库中检索许多记录并将它们显示给用户。我使用 ajax 执行此操作,并将应添加到页面的所有内容存储在单个字符串中。目前,我的加载时间有问题(每 100 条记录 1 秒)。例如,加载 1000 行需要 10 秒,而查询本身可以在不到 1 秒的时间内完全执行。这意味着瓶颈是创建元素并将它们添加到网页中。

//client side code    
$(document).ready(function () 
    loadGrid(function () 
    $(".rowCount").val($(".tbody .tr:visible").length);
);

function loadGrid(callback) 
    $.ajax(
        type: "POST", url: "Ledger.aspx/LoadGrid",
        data: "",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) 
            $(".tbody").html(response.d);   //response.d = '<div class='tr'> <div class='td colIdVchItm'>1</div>...</div>'
            callback();
        ,
        failure: function (response) 
            ShowMessage(response.d);
        
    );


//server side code
[WebMethod]
    public static string LoadGrid()
    
        string q = @"select cast((select 'tr' as [@class],  
'td colIdVchItm' as [div/@class] , a.IdVchItm as [div], ' ',
'td colNo' as [div/@class] , a.No as [div], ' ',
'td colRef' as [div/@class] ,a.Ref as [div], ' ',
'td colSeq' as [div/@class] ,a.Seq as [div], ' ',
'td colDescr' as [div/@class] ,a.Descr as [div], ' ',
'td colDebit' as [div/@class] , cast(a.Debit as decimal(38,0)) as [div], ' ',
'td colCredit' as [div/@class] , cast(a.Credit as decimal(38,0)) as [div], ' ',
'td colBalance' as [div/@class] ,null as [div] , ' ',
'td colCur' as [div/@class] ,b.Title as [div], ' ',
'td colCurVal' as [div/@class] ,a.CurVal as [div], ' ',
'td colEffDate' as [div/@class] ,dbo.ShamsiDate(a.EffectiveDate) as [div] , ' '
from a inner join Currency as b on a.IdCur = b.IdCur order by a.vchdate, a.no
for xml path('div')) as nvarchar(max))";
        // this query returns every records as an html text. for example: 
        // <div class='tr'> <div class='td colIdVchItm'>1</div>...
        string res = "";
        SqlConnection con = new SqlConnection(DAL.conStr);
        SqlCommand com = new SqlCommand(q, con);
        con.Open();
        SqlDataReader rd = com.ExecuteReader();
        rd.Read();
        res = rd[0].ToString();
        con.Close();
        return res;
    

如果您能帮助我优化此过程,我们将不胜感激。

【问题讨论】:

你的第一张桌子真的叫a吗?无论哪种方式,Currency 都以C 开头,而不是b:Bad habits to kick : using table aliases like (a, b, c) or (t1, t2, t3)。然而,这看起来你应该使用FOR XML PATH 很抱歉命名不当。但它们是真的,sql-query 不是瓶颈。 你能添加 response.d 的值吗?您能描述一下您是如何调用 loadGrid 的吗? @gaetanoM 添加。 @Behnam 你能分享 response.d 的实际值(1000 行)吗?因为它不可重现,所以我们现在不知道数据有多大。 (您可以将您的数据放入笔 (codepen.io/pen) 并分享链接。) 【参考方案1】:

@Bhenam: $(".tbody").html() 内部使用innerHTML,这需要重建DOM,但使用append() jquery 方法将内容添加到末尾该节点中的子节点。

你能试试下面的代码吗?

 success: function (response) 
            $(".tbody").html('');
             $(".tbody").append(response.d);

            callback();
        

所有浏览器都支持。 https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild

【讨论】:

【参考方案2】:

您的大部分代码看起来都不错,不应该花您提到的时间尝试查看日志,看看从服务器端加载到客户端是否需要时间。

在处理大量数据时,最重要的事情之一是您应该始终使用分页(每页加载 x 数据量)。即使您的查询需要 1-2 秒来执行,大量数据到达 UI 的时间也会根据客户端的网络连接而增加。

另一件事是,如果您只是从后端发送数据并在前端构建 html 字符串,您将节省大量加载该数据的时间,因为它要少得多。

解决前端问题的其他快速提示是:

尽可能限制访问 DOM。您正在访问 DOM 两次,一次是将 html 添加到 tbody,第二次是计算可见行的长度时,您可以通过仅从后端发送数据并计算长度并在前端创建 html 字符串来防止这种情况。您可以将其传递给加载网格回调函数。 尽可能使用 ID。当您使用类作为选择器时,它必须遍历整个 DOM 并检查该特定情况的多个情况。并且很可能您在一个地方添加了行。使用 ID,这样它就不必遍历文档的其余部分。 尝试返回false;在每个函数之后。在很多地方这并不重要,但如果你有一个巨大的 javascript 文件,这会稍微提高性能。

function() //DOM manipulation code here ..... return false;

javascript 的行为方式是,如果它没有看到任何函数返回,它会转到页面顶部并重新计算接下来要执行的函数或语句。如果您已经退货,它会自动进入下一步。

我希望这会有所帮助。如果它没有提供更多详细信息并尽可能显示性能和网络日志的屏幕截图。

【讨论】:

【参考方案3】:

您在单个请求中获取所有记录数据。您可以尝试延迟加载,而不是急切加载。

一次 200 条记录通过 ajax。请在服务器端应用限制。

    var offset = 200,page=0; 
   //client side code    
    $(document).ready(function () 
        loadGrid(function () 
        $(".rowCount").val($(".tbody .tr:visible").length);
    );

    function loadGrid(callback) 
        $.ajax(
            type: "POST", url: "Ledger.aspx/LoadGrid",
            data: offset:offset,start:page,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (response) 
               if(response)

                $(".tbody").append(response.d);   //response.d = '<div class='tr'> <div class='td colIdVchItm'>1</div>...</div>'
                callback();
                 if($(".tbody .tr:visible").length % offset == 0)
                     page++;
                     loadGrid(callback);
                  
                
            ,
            failure: function (response) 
                ShowMessage(response.d);
            
        );
    

【讨论】:

以上是关于如何优化将大量元素动态添加到网页中的主要内容,如果未能解决你的问题,请参考以下文章

如何将 DOM 元素附加到动态新添加的 DOM 元素

js中如何动态的将字典添加到列表中

如何将 jquery ui 自动完成添加到动态创建的元素?

如何将 Zend_Dojo 表单元素动态添加到 zend_form?

如何将动态 TailwindCSS 类添加到 React 中的 DOM 元素

如何在angularjs中动态地将样式属性添加到具有ng-class的元素