Javascript性能优化

wil*_*nka 6 javascript csv optimization performance function

我创建了以下js函数

function csvDecode(csvRecordsList)
{
    var cel;
    var chk;
    var chkACB;
    var chkAF;
    var chkAMR;
    var chkAN;
    var csvField;
    var csvFieldLen;
    var csvFieldsList;
    var csvRow;
    var csvRowLen = csvRecordsList.length;
    var frag = document.createDocumentFragment();
    var injectFragInTbody = function () {tblbody.replaceChild(frag, tblbody.firstElementChild);};
    var isFirstRec;
    var len;
    var newEmbtyRow;
    var objCells;
    var parReEx = new RegExp(myCsvParag, 'ig');
    var tblbody;
    var tblCount = 0;
    var tgtTblBodyID;

    for (csvRow = 0; csvRow < csvRowLen; csvRow++)
    {
        if (csvRecordsList[csvRow].startsWith(myTBodySep))
        {
            if (frag.childElementCount > 0)
            {
                injectFragInTbody();
            }
            tgtTblBodyID = csvRecordsList[csvRow].split(myTBodySep)[1];
            newEmbtyRow = getNewEmptyRow(tgtTblBodyID);
            objCells = newEmbtyRow.cells;
            len = newEmbtyRow.querySelectorAll('input')[0].parentNode.cellIndex; // Finds the cell index where is placed the first input (Check-box or button)

            tblbody = getElById(tgtTblBodyID);
            chkAF = toBool(tblbody.dataset.acceptfiles);
            chkACB = toBool(tblbody.dataset.acceptcheckboxes) ;
            chkAN = toBool(tblbody.dataset.acceptmultiplerows) ;
            tblCount++;
            continue;
        }

        csvRecordsList[csvRow] = csvRecordsList[csvRow].replace(parReEx, myInnerHTMLParag); // Replaces all the paragraph symbols ¶ used into the db.csv file with the tag <br> needed into the HTML content of table cells, this way will be possible to use line breaks into table cells
        csvFieldsList = csvRecordsList[csvRow].split(myEndOfFld);

        csvFieldLen = csvFieldsList.length;
        for (csvField = 0; csvField < csvFieldLen; csvField++)
        {
            cel = chkAN ? csvField + 1 : csvField;
            if (chkAF && cel === 1) {objCells[cel].innerHTML =  makeFileLink(csvFieldsList[csvField]);} 
            else if (chkACB && cel === len) {objCells[cel].firstChild.checked = toBool(csvFieldsList[csvField]);}
            else {objCells[cel].innerHTML = csvFieldsList[csvField];}
        }
        frag.appendChild(newEmbtyRow.cloneNode(true));
    }
    injectFragInTbody();

    var recNum = getElById(tgtTblBodyID).childElementCount;
    customizeHtmlTitle();
    return csvRow - tblCount + ' (di cui '+ recNum + ' record di documenti)';
}
Run Code Online (Sandbox Code Playgroud)

超过90%的记录可能包含必须由以下makeFileLink函数处理的文件名:

function makeFileLink(fname)
{
    return ['<a href="', dirDocSan, fname, '" target="', previewWinName, '" title="Apri il file allegato: ', fname, '" >', fname, '</a>'].join('');
}
Run Code Online (Sandbox Code Playgroud)

它旨在从特殊类型的*.db.csv文件中解码记录列表(=以逗号分隔的值,其中逗号被另一个硬编码到var myEndOfFld中的符号替换).(这种特殊类型的*.db.csv是由我写的另一个函数创建的,它只是一个"文本"文件).

解码和附加到HTML表的记录列表通过其单独的参数传递给函数:(csvRecordsList).

进入csv文件的是来自更多HTML表的托管数据.

表的行数和列数以及其他一些包含的数据类型(可以是文件名,数字,字符串,日期,复选框值)不同.

有些表可能只有1行,有些表接受更多行.

一行数据具有以下基本结构:

data field content 1|data field content 2|data field content 3|etc...
Run Code Online (Sandbox Code Playgroud)

一旦我的算法解码,它将被正确地呈现到HTML td元素中,即使在字段中有更多段落.事实上,标签
将添加到代码所需的位置:

csvRecordsList[csvRow].replace(par, myInnerHTMLParag)
Run Code Online (Sandbox Code Playgroud)

取代我选择代表我已硬编码到变量中的段落符号的所有char myCsvParag.

在编程时不可能知道每个表中要加载的记录数,也不能知道从CSV文件加载的记录数,也不知道每个记录的字段数或者哪个表字段将包含数据或将为空:在同一记录中,某些字段可能包含其他可能为空的数据.必须在运行时发现一切.

进入特殊的csv文件,每个表与下一个表分隔一行,其中只包含一个具有以下模式的字符串:myTBodySep = tablebodyid其中myTBodySep ="targettbodydatatable",这只是我选择的硬编码字符串.tablebodyid只是一个占位符,它包含一个字符串,表示要插入新记录的目标表tbody元素的id,例如:tBodyDataCars,tBodyDataAnimals ......等.

因此,当第一个for循环找到csvRecordsList时,一个字符串与字符串一起进入变量myTBodySep,它从同一行获取tablebodyid:这将是新的tbodyid,必须用于注入其中的下一个记录

每个表都存档到CSV文件中

第一个for循环从文件中扫描csv记录列表,第二个for循环准备用数据编译目标表所需的内容.

上面的代码运行良好,但有点慢:事实上,从CSV文件中加载大约300条记录的HTML表格,在2 GB RAM和Pentium core 2 4300 dual的计算机上需要2.5秒多一点核心在1800 MHz,但如果我评论更新DOM的行,该功能需要不到0.1秒.所以恕我直言,瓶颈是片段和DOM操纵代码的一部分.

我的目标和希望是在不失去功能的情况下优化上述代码的速度.

请注意,我的目标只是现代浏览器,我不关心其他浏览器和非标准兼容的浏览器...我为他们感到遗憾......

有什么建议?提前致谢.

编辑16-02.2018

我不知道它是否有用但最后我注意到,如果从浏览器会话存储中加载数据,则加载和渲染时间或多或少减半.但奇怪的是,它是从文件和sessionstorage加载数据的完全相同的函数.我不明白为什么这种不同的行为考虑到数据完全相同,并且在开始检查性能时序之前,在两种情况下都被传递给由函数本身处理的变量.

编辑18.02.2018

  1. 行数根据目标表而变化:从1到1000(在特定情况下可能更多)
  2. 列数取决于目标表:从10到18-20

Kos*_*ery 5

事实上,使用DOM操作构建表比简单innerHTML更新表元素要慢.

如果您尝试重写代码以准备html字符串并将其放入表的innerHTML中,您会看到显着的性能提升.

浏览器经过优化,可以解析text/html从服务器接收的内容,因为它是主要目的.通过JS进行DOM操作是次要的,因此它们不是那么优化的.

我为你做了一个简单的基准测试.

让我们制作一张300x300的桌子并用'A'填充90000个单元格.有两个功能.

第一个是代码的简化变体,它使用DOM methods:

var table = document.querySelector('table tbody');
var cells_in_row = 300, rows_total = 300;

var start = performance.now();
fill_table_1();
console.log('using DOM methods: ' + (performance.now() - start).toFixed(2) + 'ms');

table.innerHTML = '<tbody></tbody>';


function fill_table_1() {
  var frag = document.createDocumentFragment();

  var injectFragInTbody = function() {
    table.replaceChild(frag, table.firstElementChild)
  }

  var getNewEmptyRow = function() {
    var row = table.firstElementChild;
    if (!row) {
      row = table.insertRow(0);
      for (var c = 0; c < cells_in_row; c++) row.insertCell(c);
    }
    return row.cloneNode(true);
  }

  for (var r = 0; r < rows_total; r++) {
    var new_row = getNewEmptyRow();
    var cells = new_row.cells;
    for (var c = 0; c < cells_in_row; c++) cells[c].innerHTML = 'A';
    frag.appendChild(new_row.cloneNode(true));
  }
  injectFragInTbody();
  return false;
}
Run Code Online (Sandbox Code Playgroud)
<table><tbody></tbody></table>
Run Code Online (Sandbox Code Playgroud)

第二个准备html字符串并将其放入表中innerHTML:

var table = document.querySelector('table tbody');
var cells_in_row = 300, rows_total = 300;

var start = performance.now();
fill_table_2();
console.log('setting innerHTML: ' + (performance.now() - start).toFixed(2) + 'ms');

table.innerHTML = '<tbody></tbody>';

function fill_table_2() {// setting innerHTML
  var html = '';
  for (var r = 0; r < rows_total; r++) {
    html += '<tr>';
    for (var c = 0; c < cells_in_row; c++) html += '<td>A</td>';
    html += '</tr>';
  }
  table.innerHTML = html;
  return false;
}
Run Code Online (Sandbox Code Playgroud)
<table><tbody></tbody></table>
Run Code Online (Sandbox Code Playgroud)

我相信你会得出一些结论.


Nie*_*Bom 2

我有两个想法要告诉你。

1:如果您想知道代码的哪些部分(相对)较慢,您可以使用此处描述的技术进行非常简单的性能测试。我没有阅读您提供的所有代码示例,但您可以自己添加这些性能测试并检查哪些操作需要更多时间。

2:我对JavaScript和浏览器的了解是,改变DOM是一个昂贵的操作,你不想改变DOM太多次。相反,您可以做的是构建一组更改,然后通过一次 DOM 更改应用所有这些更改。这可能会使您的代码不太好,但这通常是您想要获得高性能时必须进行的权衡。

让我知道这对你来说效果如何。