【Web前端问题】大批量DOM操作如何提升性能

START
Q:很简单的一个业务,用JS实现一个通讯录的列表显示。
具体描述:
1.A-Z+#,一共27个DOM对象,假设有1000条数据,我要根据数据中的姓名往这27个DOM对象中添加,请问如何可以最高效的实现,头像可以后加载因此这里不考虑。
2.拒绝setTimeout来实现
3.因为要分别往多个DOM对象中进行DOM操作,所以除了创建多个DocumentFragment来实现外,是否有其他方法来提高性能。
4.个人尝试使用Promise来实现,然而并没有起到想要的结果。
5.代码如下:

var index = "ABCDEFGHIJKLMNOPQRSTUVWXYZ#";

for (var i in data) {

if (index.indexOf(data[i].per_allpinyin[0].toUpperCase()) >= 0) {

document.getElementById(data[i].per_allpinyin[0].toUpperCase()).appendChild(dataname(i));

} else

document.getElementById("#").appendChild(dataname(i));

}

6.因为DOM的操作永远是同步渲染的,因此在数据>1000的时候,页面的渲染会有些卡顿,因此寻求帮助。
END

first ADD:
感谢几个大大关于分批次的建议,不过我之前忘记补充了。
7.因为右侧有一个快捷侧边栏,可以实现用户点击首字母马上跳转,因此分批次实现的话就会造成一个很糟糕的用户体验,即用户点击Z侧边栏的时候,却发现Z的数据还没有加载进来,所以处于业务需求,暂时不会考虑分批次。包括按首字母分批次和按数据分批次

回答:

这两天又用了各种方法尝试了下
1.发现同步操作的话,还是documentfragment效率最高,但是同步加载的情况下,加载过程中渲染的卡顿还是无可避免。
2.如果使用setTimeout或者requestAnimateFrame来达到异步实现的话,会造成后面绑定事件的业务变动,而且对于非动画操作,其实两者效率差不多,每秒60帧也已经是极限了。这样的帧数下,用递归实现的话,1000条数据就需要至少20+s才能加载完成,不过DOM的渲染会较为流畅,然而不管是侧边栏和还是用户滚动操作都不符合本业务,所以放弃。
3.其实DOM的生成还是较快的,1k+条数据的生成大概在1s-2s之间就可以完成,主要还是后续事件绑定的代码会影响单进程的JS执行,导致页面渲染变慢。
END:所以最终DOM上还是采用多documentfragment来实现,而后续事件句柄则采用setTimeout来异步加载,使得界面先生成而事件绑定不影响页面的渲染。
PS:最后感谢大家的帮忙,希望我所发现的这个问题可以帮到大家

回答:

可以考虑建立一个数据队列,把1000条数据分片处理,中间加loading动画之类的把使渲染过程流畅起来,或者做一个分页。

比较推荐做分页。

回答:

你可以设置几个断点,分批滚动加载。比如:5个一组,前5个ABCDE最先渲染。页面滚动到F进入可视区域时,将FGHIJ插入进来。依次类推。
你可能需要了解一下,滚动时DOM节点是否位于可视区域内的判断,以及滚动时优化。

回答:

分批加载。

    // 分时函数

function timedChunk(items, process, context, callback) {

var todo = items.concat(), delay = 25;

setTimeout(function() {

var start = +new Date();

do {

process.call(context, todo.shift());

} while (todo.length > 0 && (+new Date() - start < 50))

if(todo.length > 0) {

setTimeout(arguments.callee, 25);

} else if(callback) {

callback();

}

}, delay);

}

分时加载是腾讯qq网页版用的加载好友的方式,应该还是比较适合的。

const data = [1, 2, 3, 4, 4, 4, 5, 56, 6];//这是你要加载的数据

const dalay = 50;//这是每加载一批数据的时间间隔

let interval = setInterval(() => chunkData(data, num, callback), dalay);//分时加载

function chunkData(data, num, callback) {//num是每次加载的数量,callcack是执行的函数就算你appendChild操作的函数

let arr;

if (data.length > num) {

arr = data.splice(0, num);

} else if (data.length <= num && data.length > 0) {

arr = data.splice(0);

} else {

clearInterval(interval);

}

callback(data);

}

图片描述图片描述

回答:

虽然不清楚具体的业务场景,但是都大1000 了 ,如果是数据渲染的话,那还不做分页,这有点难搞了,setTimeout 还不让想用,那就没办法了,除非做一个节流函数,但是节流函数的本身还是用时间来控制数据的

我同意二楼的观点

回答:

可以用innerHTML来代替高频繁的appendChild

回答:

虚拟dom就好了 分页加载 每次加载一页大概十来个数据 再往下滑动就再去加载 iscroll有现成的方法 或者自己写个

回答:

全部拼接成字符串再 放到innerHtml呢?

回答:

没写过, 可不可以后台推送数据时候根据首字母分组, 你这里前端渲染的时候根据分组以首字母为单位分块渲染, 即使点击首字母也可以快速定位到指定组.
大概这样的数据

[{aaaaa},{bbbbbb},{ddddddd}]

回答:

第一当然首选定时器,不过已经被你把最优的方法排除了。那么只有使用Web Workers生成整体的HTML片段再一次性append到DOM里

回答:

业务上的需求不能给你砍掉。所以建议都放到requestAnimateFrame中去,这样保证渲染流畅度,不会让用户卡顿

回答:

(我来乱答的...)那就丢去服务器渲染?

回答:

个人认为就目前设计来说功能和体验可能需要有取舍,所有数据单页显示的情况下,当你跳转后排数据的时候:

  1. 分批顺序加载,前面数据未加载完时,可以给个加载等候;
  2. 优先加载选定数据的话,你要解决前排数据占位的问题
    如果1不能满足你的要求,2无法解决,又没其他手段的情况下,修改设计可能更容易满足业务需求和用户体验

回答:

你知道弹幕是怎么实现的么

回答:

一般有资源文件加载的标签,可以做个onload监听,加载完成达到多少再继续添加,可以把要添加的dom数据放进一个数组,使用数组的slice方法来解决效果也不错的

回答:

事件这块可以使用事件委托进行优化

以上是 【Web前端问题】大批量DOM操作如何提升性能 的全部内容, 来源链接: utcz.com/a/143118.html

回到顶部