使用JavaScript无阻塞地附加DOM元素

使用JavaScript无阻塞地附加DOM元素,javascript,dom,Javascript,Dom,我想用异步JavaScript追加2000个表行。这需要大约3秒钟的时间,所有的UI控件都被阻塞在页面内。我可以在没有阻塞的情况下附加到DOM吗 如您所见,演示中的复选框仅在3-4秒后才能单击: 演示中包含的内容: function populateTable() { for (var i = 0; i < 4*1000; i++) { var tr = $('<tr></tr>'); ... tr.appendTo(table);

我想用异步JavaScript追加2000个表行。这需要大约3秒钟的时间,所有的UI控件都被阻塞在页面内。我可以在没有阻塞的情况下附加到DOM吗

如您所见,演示中的复选框仅在3-4秒后才能单击:

演示中包含的内容:

function populateTable() {
  for (var i = 0; i < 4*1000; i++) {
    var tr = $('<tr></tr>');
    ...
    tr.appendTo(table);
  }
}
setTimeout(populateTable, 0); // async
函数populateTable(){
对于(变量i=0;i<4*1000;i++){
var tr=$('');
...
tr.appendTo(表);
}
}
setTimeout(populateTable,0);//异步的

其思想是将表分块填充,然后让UI在块之间更新。这允许用户与复选框交互并查看表格填充情况,而不是盯着一个没有响应的UI的空白页面

您可以修改变量以找到可接受的用户体验。这个答案使用,如果你不熟悉它们,我建议你学习,因为它非常有用。这里的权衡是,填充表需要更长的时间,但这是值得的

编辑:我建议将表构建为一个字符串,并且只插入一次,因为它很快,就像其他答案一样。然而,这种异步“块”加载方法是一种很好的模式

var t1 = new Date().getTime();
var log = console.log;
var table = $('#the-table');
var rows = 4000
var columns = 10
var chunk = 100
var timeout = 50

async function populateTable() {
  let totalRows = rows
  while(totalRows > 0){
    await addChunk()
    totalRows -= chunk
  }
  log('table populated at ', (new Date().getTime() - t1), 'ms');
}

function addChunk(){
    return new Promise(resolve=>{
    setTimeout(()=>{
      for (var i = 0; i < chunk; i++) {
        var tr = $('<tr></tr>');
        for (var j = 0; j < columns; j++) {
          var td = $('<td></td>');
          td.text('' + i + '_' + j);
          td.appendTo(tr);
        }
        tr.appendTo(table);
        resolve()
      }
    },timeout)
  })
}

setTimeout(populateTable, 0);
var t1=new Date().getTime();
var log=console.log;
变量表=$(“#表”);
var行数=4000
变量列=10
var chunk=100
变量超时=50
异步函数populateTable(){
让totalRows=行
而(总计行数>0){
等待addChunk()
totalRows-=块
}
日志('表填充在',(new Date().getTime()-t1),'ms');
}
函数addChunk(){
返回新承诺(解决=>{
设置超时(()=>{
对于(var i=0;i
首先使用vanilla JS(更快),一次插入HTML,而不是将每一行、td和文本分别插入数千次:

const t1 = new Date().getTime();
const log = console.log;
const table = document.querySelector('#the-table');
function populateTable() {
  const trStrings = [];
  for (let i = 0; i < 4000; i++) {
    const tdValues = [];
    for (let j = 0; j < 10; j++) {
      tdValues.push(i + '_' + j);
    }
    trStrings.push('<tr><td>' + tdValues.join('</td><td>') + '</td></tr>');
  }
  table.innerHTML = trStrings.join('');
  log('table populated at ', (new Date().getTime() - t1), 'ms');
}
setTimeout(populateTable, 0);
const t1=new Date().getTime();
const log=console.log;
const table=document.querySelector(“#表”);
函数populateTable(){
常量trStrings=[];
for(设i=0;i<4000;i++){
常量tdValues=[];
for(设j=0;j<10;j++){
tdValues.push(i+'.'+j);
}
trStrings.push(“”+tdValues.join(“”)+“”);
}
table.innerHTML=trStrings.join(“”);
日志('表填充在',(new Date().getTime()-t1),'ms');
}
setTimeout(populateTable,0);

统计数据:

(索引):在79毫秒时填充80个表

(索引):在78毫秒时填充80个表格

(索引):在77毫秒时填充80个表格

(索引):在73毫秒时填充80个表

(索引):81毫秒时填充80个表

从某种意义上说,它仍然是“阻塞”,如果需要,它仍然可以被解决,但它的数量级更快,因此阻塞问题不那么令人担忧


但如果可能的话,这确实应该通过服务器提供,而不是通过Javascript进行动态解析和呈现。

哇,我迟到了。作为类似的回答,我使用vanilla JS、promise和函数式编程更快地绘制表格

非阻塞的一个关键原因是表应该在内存中创建。将TR插入此内存表中。最后,循环完成后,将表插入DOM。代码如下:

const generateTable = () => {
    return new Promise((resolve) => {
        const table = document.createElement('table');
        const column = Array.from({ length: 4000}, (v, i) => i);
        const row = Array.from({ length: 10}, (v, i) => i);

        column.forEach((col, i) => {
            const tr = document.createElement('tr');

            row.forEach((r, j) => {
                const td = document.createElement('td');

                td.innerHTML = `${i}-${j}`;
                tr.appendChild(td);
            })

         table.appendChild(tr);
    })

    table.id = 'the-table';
    resolve(table);
  })
}

const t1 = new Date().getTime();
generateTable()
    .then(table => {
    document.body.appendChild(table);
    console.log('table populated at ', (new Date().getTime() - t1), 'ms');
  })
  • 如果您想快速加载某些内容,请不要使用jQuery,而是使用普通JavaScript
  • 如果您正在与DOM交互,请执行一次而不是44000次
  • 从表的子元素
    开始,创建需要插入到表中的所有内容。将
    的内容添加到(4000行+40000个单元格)中后,创建一个
  • 此时,浏览器已在@100ms的范围内执行44002条语句,作为SO或@60ms上的堆栈片段★ 作为一个不受欢迎的人但浏览器甚至还没有触及DOM。
  • 要执行的最后一条语句是将docFrag附加到
    。这是唯一提交的DOM交互
  • 在DOM中,只向
    添加一个
    一次是在公园里散步
  • 在DOM中,将4000和40000追加到
    中是非常昂贵的
  • 请注意,脚本位于
    结束标记之前,因此不需要考虑阻塞
  • ★ 第一次测试为100ms,第二次测试为80ms,第三次测试为60ms

    演示-查看此文件以加快加载速度
    
    用户界面
    var t0=新日期().getTime();
    var frag=document.createDocumentFragment();
    var tb=document.createElement('tbody');
    for(设i=0;i<4000;i++){
    const tr=document.createElement('tr');
    for(设j=0;j<10;j++){
    const td=document.createElement('td');
    td.textContent=`i}{j}`;
    tr.appendChild(td);
    }
    儿童结核病;
    }
    肺结核;
    文件.getElementById('table01').appendChild(frag);
    var t1=new Date().getTime();
    document.getElementById('msg')。value=`插入所用的时间:${t1-t0}`;
    
    将它们附加到tbody元素,然后将该tbody元素附加到表中。