写在前面
昨天(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,兼容性会有些问题