0%

时间分片

写在前面

昨天(2020-9-19)看2019vueconf的时候,尤大在分享vue3的特点的时候,提到了vue和react在底层针对模板编译和jsx优化的一些不同的时候提到了一个词,时间分片;然后就做了一点功课,写个笔记。

正文

解决了什么?

  • js会阻塞ui的渲染,所以当一个操作耗时非常长时,就会造成页面内容显示滞后,带来很不好的用户体验
  • 通过将操作划分为一个个小的阶段,来执行

怎么做的?

实例

实例描述:通过js插入10000个li到ul中

使用最普通的循环插入

1
2
3
4
5
6
7
8
9
10
11
<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>

使用定时器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<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,兼容性会有些问题