React18原理: 时间分片技术选择

渲染1w个节点的不同方式


1 )案例1:一次渲染1w个节点

<div id='root'><div>

<script type="text/javascript">
	function randomHexColor() {
     
		return "#" + ("0000"+ (Math.random() * 0x1000000 << 0).toString(16)).substr(-6);
	}

	setTimeout(function() {
     
		var k = 0;
		var root = document.getElementById("root");
		for(var i = 0; i < 10000; i++) {
     
			k += new Date - 0 ;
			var el = document.createElement("div");
			el.innerHTML = k;
			root.appendChild(el);
			el.style.cssText = `background: ${ randomHexColor()};height: 40px`;
		}
	},1000);
</script>

1 次完成 1w 个节点的渲染

可以看到,圈中的部分,明显被阻塞,这一块绝对会导致用户体验很差

2 )案例2: 1w 个节点分100次执行,每次执行100个

<div id='root'><div>

<script type="text/javascript">
	var root = document.getElementById("root");

	function randomHexColor() {
     
		return "#" + ("0000"+ (Math.random() * 0x1000000 << 0).toString(16)).substr(-6);
	}

	function loop(n) {
     
		var k = 0;
		console.log(n);
		for(var i = 0; i < 100; i++) {
     
			k += new Date - 0 ;
			var el = document.createElement("div");
			el.innerHTML = k;
			root.appendChild(el);
			el.style.cssText = `background: ${ randomHexColor()};height: 40px`;
		}
		if (n) {
     
			// 内部再调用 n-1次 loop,总计调用 n 次 loop
			setTimeout(function() {
     
				loop(n - 1);
			}, 40)
		}
	}

	// 1s 执行一次
	setTimeout(function() {
     
		loop(100)
	}, 1000);
</script>
  • 这里,40ms 执行一次,100次,共4s执行完成
  • 可以看到,没有明显的阻塞

为什么会有如此区别

  • 究其原因是因为浏览器是单线程,它将GUI描绘,时间器处理,事件处理,JS执行远程资源加载统统放在一起,当做某件事,只有将它做完才能做下一件事
  • 如果有足够的时间,浏览器是会对我们的代码进行编译优化(JIT) 及进行热代码优化,一些DOM操作,内部也会对reflow进行处理
  • reflow是一个性能黑洞,很可能让页面的大多数元素进行重新布局
  • 所以,浏览器歇一会儿跑一会儿,比一直跑性能更好

时间分片技术方案选择


1 )注意兼容问题

  • 注意,在 request18 版本并没有使用 requestIdleCalback, 仍旧因为兼容问题

2 ) 方案选择

  • 在浏览器环境中,常见的macro task有setTimeout、MessageChannel、postMessage
  • 而常见的 micro task 有 MutationObsever, Promise.then

2.1 微任务问题

  • 为什么不使用微任务呢?
  • 宏任务是在下一轮事件循环中执行,微任务是在当前时间循环中执行
  • 微任务将在页面更新前全部执行完,也就是是要在当前帧执行完的,所以达不到「将主线程还给浏览器」的目的
  • 使用微任务就会造成一个问题,在极端情况下,一直卡在当前帧,因为微任务是在当前帧执行完的(本轮事件循环内)
  • 所以在 setTimeout, MessageChannel, postMessage 三选一
  • 为什么不使用setTimeout(fn,0)呢?
    function timer() {
         
      console.ltme('计时器')
      setTimeout(() => {
         
        console.timeEnd('计时器')
        timer()
      }, 0)
    }
    
    timer()
    
    • 递归的setTimeout()调用会使调用间隔变为4ms,导致浪费了4ms
    • 这是一个递归的定时器,在递归的时候,看下它的间隔时间
    • 在定时器递归大约4次以后,它的递归时间就变成了4ms~ 5ms 变得不准确
    • 明明我们指定的是 0ms, 这里差距有些大了,所以这个api有些问题,误差太大

2.2 宏任务问题

  • 为什么不使用 rAF() 呢?

    • 如果上次任务调度不是rAF()触发的,将导致在当前帧更新前进行两次任务调度
    • 页面更新的时间不确定,如果浏览器间隔了10ms才更新页面,那么这10ms就浪费了
  • React Scheduler使用MessageChannel的原因为:生成宏任务,实现:

    • 将主线程还给浏览器,以便浏览器更新页面
    • 浏览器更新页面后继续执行未完成的任务
      const {
              port1, port2 } = new MessageChannel();
      
      port1.onmessage = function (event){
             
        console.log('收到来自port2的消息:', event.data);//收到来自port2的消息: pong
      };
      
      port2.onmessage = function (event) {
             
        console.log('收到来自port1的消息:', event.data);//收到来自port1的消息: ping
        port2.postMessage('pong');
      };
      port1.postMessage('ping');
      

相关推荐

  1. antd DatePicker 日期 与 时间 分开选择

    2024-02-14 11:42:03       10 阅读
  2. React底层原理分析(简单大白话版本)

    2024-02-14 11:42:03       32 阅读
  3. <span style='color:red;'>React</span> <span style='color:red;'>18</span>

    React 18

    2024-02-14 11:42:03      8 阅读
  4. React原理

    2024-02-14 11:42:03       32 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-14 11:42:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-14 11:42:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-14 11:42:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-14 11:42:03       18 阅读

热门阅读

  1. 14.6 OpenGL图元装配和光栅化:多边形

    2024-02-14 11:42:03       25 阅读
  2. 14.5 OpenGL图元装配和光栅化:线段

    2024-02-14 11:42:03       28 阅读
  3. c语言练习

    2024-02-14 11:42:03       29 阅读
  4. MD5 哈希

    2024-02-14 11:42:03       25 阅读
  5. Git入门

    Git入门

    2024-02-14 11:42:03      29 阅读
  6. free pascal:fpwebview 组件简单易用

    2024-02-14 11:42:03       35 阅读
  7. QT自定义信号和槽

    2024-02-14 11:42:03       29 阅读
  8. 蓝桥杯每日一题----素数筛

    2024-02-14 11:42:03       30 阅读
  9. Android:自定义控件

    2024-02-14 11:42:03       28 阅读
  10. 算法笔记P67

    2024-02-14 11:42:03       28 阅读
  11. 兵棋推演是离散问题,深度学习是连续问题

    2024-02-14 11:42:03       31 阅读
  12. Gateway中Spring Security6统一处理CORS

    2024-02-14 11:42:03       29 阅读