写在前面
昨天(2020-9-19)看2019vueconf的时候,尤大在分享vue3的特点的时候,提到了vue和react在底层针对模板编译和jsx优化的一些不同的时候提到了一个词,时间分片;然后就做了一点功课,写个笔记。
正文
解决了什么?
- js会阻塞ui的渲染,所以当一个操作耗时非常长时,就会造成页面内容显示滞后,带来很不好的用户体验
- 通过将操作划分为一个个小的阶段,来执行
怎么做的?
- 利用异步的一些api
- settimeout
- requestIdleCallback
- requestAnimationFrame
实例
实例描述:通过js插入10000个li到ul中
使用最普通的循环插入
<ul class="list"></ul>
<script>
"use strict";
let list = document.querySelector(".list");
let total = 100000;
for (let i = 0; i < total; ++i) {
let item = document.createElement("li");
item.innerText = `我是${i}`;
list.appendChild(item);
}
</script>
使用定时器
<ul class="list"></ul>
<script>
"use strict";
let list = document.querySelector(".list");
let total = 100000;
const render = (start, end) => {
if (end < total) {
setTimeout(() => {
let frag = document.createDocumentFragment();
for (let i = start; i < end; ++i) {
let item = document.createElement("li");
item.innerText = `我是${i}`;
frag.appendChild(item);
}
list.appendChild(frag);
render(end + 1, end + 20);
}, 10);
}
};
render(0, 20);
</script>
使用requestAnimationFrame
<ul class="list"></ul>
<script>
"use strict";
let list = document.querySelector(".list");
let total = 100000;
let size = 20;
let index = 0;
const render = (total, index) => {
if (total <= 0) {
return;
}
let curPage = Math.min(total, size);
window.requestAnimationFrame(() => {
let fragment = document.createDocumentFragment();
for (let i = 0; i < curPage; ++i) {
let item = document.createElement("li");
item.innerText = `我是${index + i}`;
fragment.appendChild(item);
}
list.appendChild(fragment);
render(total - curPage, index + curPage);
});
};
render(total, index);
</script>
总结
- 时间分片就是讲耗时的长任务,划分为一个个耗时很短的小任务;将处理结果一点点返回给用户
- 主要的手段就是利用js的event loop机制,通过异步的一些操作来处理切分任务
其他
关于requestAnimationFrame和setInterval处理动画的区别
- 帧率和循环的事件交由浏览器控制,可以更好的控制的帧率
- 性能流畅度更优秀
- 新api,兼容性会有些问题