jsDOM批量插入节点性能测试

测试配置:
cpu:Intel(R) Core(TM) i7-9750H CPU @2.60GHz
gpu:GTX1650 4G
内存:DDR4 2667MHz
浏览器:Chrome 版本 87.0.4280.141

// 测试执行耗时方法
function getRunTime(fun) {
    const start = new Date().getTime();//起始时间
    fun();//执行待测函数
    const end = new Date().getTime();//结束时间
    return (end - start) + "ms";//返回函数执行需要时间
}
const body = document.body;

// 方法1:拼接字符串后innerHTML一次性添加
function strTest() {
    let str = '';
    for (let i = 0; i < 299999; i++) {
        str += '<p>Test</p>';
    }
    body.innerHTML = str;
}

// 方法2:数组添加值后join转字符串再innerHTML一次性添加
function arrTest() {
    const arr = [];
    for (let i = 0; i < 299999; i++) {
        arr.push('<p>Test</p>');
    }
    body.innerHTML = arr.join('');
}

// 方法3:使用DOM API插入
function domTest() {
    for (let i = 0; i < 299999; i++) {
        const p = document.createElement('p');
        p.innerHTML = 'Test';
        body.appendChild(p);
    }
}

// 方法4:使用fragment文档碎片机制
function fragmentTest() {
    const fragment = document.createDocumentFragment();
    for (let i = 0; i < 299999; i++) {
        const p = document.createElement('p');
        p.innerHTML = 'Test';
        fragment.appendChild(p);
    }
    body.appendChild(fragment);
}
// 方法1速度
let strTestTime = getRunTime(strTest);
console.log('strTestTime', strTestTime);
// 多次测试strTestTime 411ms strTestTime 447ms strTestTime 489ms strTestTime 455ms strTestTime 450ms

// 方法2速度
let arrTestTime = getRunTime(arrTest);
console.log('arrTestTime', arrTestTime);
// 多次测试arrTestTime 472ms arrTestTime 451ms arrTestTime 466ms arrTestTime 466ms arrTestTime 496ms

// 方法3速度
let domTestTime = getRunTime(domTest);
console.log('domTestTime', domTestTime);
// 多次测试domTestTime 1271ms domTestTime 1313ms domTestTime 1253ms domTestTime 1178ms domTestTime 1227ms

// 方法4速度
let fragmentTestTime = getRunTime(fragmentTest);
console.log('fragmentTestTime', fragmentTestTime);
// 多次测试fragmentTestTime 1320ms fragmentTestTime 1379ms fragmentTestTime 1248ms fragmentTestTime 1309ms fragmentTestTime 1264ms

上面的测试是分开进行的,比如测试方法1的时候会把其他代码注释掉,下面把注释全部打开同时测试:





无论怎样测试都会发现,速度由快到慢是:方法1字符串拼接 --> 方法2数组+字符串 --> 方法3DOM API和方法4fragment文档碎片机制(方法3、4没看出来究竟谁快,按理说方法4fragment文档碎片机制会快一些,但每次的对比结果都不太一样),网上有的说字符串拼接最慢,数组+字符串最快,因为字符串拼接规则是新建一个暂时字符串把str和后面的字符串拼接赋给新的暂时字符串再销毁原始字符串并赋值给str,这样子的效率是低下的,而数组添加元素方法push执行时是在浏览器中了,他是由底层语言写的,会更快。但我将测试环境配置也写了,实际情况却是字符串最快,也希望能抛砖引玉。
最后说一下,在测试时控制台已经输出了耗时,但页面实际并没有渲染出来,会再延迟一会儿再渲染,耗时方法并没有错,这是同步的,并非异步,使用console.time配合console.timeEnd,测试耗时方法并无问题

console.time('strTestTime');
let strTestTime = getRunTime(strTest);
console.timeEnd('strTestTime');
console.log('strTestTime', strTestTime);

结果:

我又手动测试了实际耗时,实际和上面的测试结果差距不大
实际开发中一般也不会同时操作大量元素节点,再又如删除元素节点、添加元素节点在合适的场景下通过更改css的display:none等手段会更好
但现在MVVM开发模式中有数据双向绑定,dom的操作ViewModel层已经帮我们做了,我们也不用考虑这些问题,又比如用户操作改变dom在React中,有他自己的虚拟dom,用户在对dom的操作实际上是对虚拟dom的操作,
用户的操作产生的数据改变或者state变量改变都会应用到虚拟dom上,之后再批量的对这些更改进行diff算法计算,对比操作前后的虚拟dom树,把更改后的变化再同步到真实dom上。
也就是说在虚拟dom上执行多次修改,在真实dom中,只会执行一次dom操作,因为在React虚拟dom机制中,它会把所有的操作都合并,只会对比刚开始的状态和最后操作的状态,两者中找出不同,然后再同步到真实dom中。

posted @ 2021-01-08 17:36  是明啊  阅读(349)  评论(0编辑  收藏  举报