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 次 loopsetTimeout(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的消息: pingport2.postMessage('pong');
      };
      port1.postMessage('ping');
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/467894.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单片机学习笔记---DS18B20温度传感器

目录 DS18B20介绍 模拟温度传感器的基本结构 数字温度传感器的应用 引脚及应用电路 DS18B20的原理图 DS18B20内部结构框图 暂存器内部 单总线介绍 单总线电路规范 单总线时序结构 初始化 发送一位 发送一个字节 接收一位 接收一个字节 DS18B20操作流程 指令介…

OpenAI宣布ChatGPT新增记忆功能;谷歌AI助理Gemini应用登陆多地区

&#x1f989; AI新闻 &#x1f680; OpenAI宣布ChatGPT新增记忆功能&#xff0c;可以自由控制内存&#xff0c;提供个性化聊天和长期追踪服务 摘要&#xff1a;ChatGPT新增的记忆功能可以帮助AI模型记住用户的提问内容&#xff0c;并且可以自由控制其内存。这意味着用户不必…

【C++第二阶段】空指针访问成员函数常成员函数常成员属性

你好你好&#xff01; 以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 空指针访问成员函数常成员函数&常成员属性 空指针访问成员函数 类对象类型的空指针可以访问成员函数&#xff0c;但是不能够访问带有成员属性的成员函数。…

算法刷题:复写零

复写零 .习题链接题目描述算法原理初始值步骤1步骤2我的答案: . 习题链接 复写零 题目描述 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素…

【C++】内存详解(堆,栈,静态区)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【DDD】学习笔记-事件风暴与领域分析建模

在确定了全景事件流之后&#xff0c;可以在战略设计层面继续精进&#xff0c;鉴别出领域与限界上下文的边界&#xff0c;进入战术设计阶段的领域分析建模。 事件风暴的分析模型要素 通过事件风暴进行领域分析建模&#xff0c;其核心的模型要素就是“事件”。除此之外&#xf…

CUDA编程 - 共享内存 - shared memory - 学习记录

CUDA编程 - 共享内存 共享内存一、为什么要使用 shared memory&#xff1f;1.1、从硬件出发理解&#xff1a;1.2、从软件出发理解&#xff1a; 二、如何使用shared memory2.1、静态共享内存2.2、动态共享内存 三、实践 - 使用共享内存执行矩阵乘法总结 共享内存 一、为什么要使…

基于 Python 深度学习的电影评论情感分析系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

13. 【Linux教程】移动文件和目录

移动文件和目录 前面小节介绍了如何创建文件和目录、删除文件和目录&#xff0c;本小节介绍如何使用 mv 命令移动文件和目录。 1. 移动文件或目录至另外一个目录下 可以使用 mv file_name 路径 这种格式&#xff0c;移动文件至其他目录下&#xff0c;后面跟的路径可以是相对路…

政安晨:【详细解析】【用TensorFlow从头实现】一个机器学习的神经网络小示例【解构演绎】

准备工作 咱们将通过这篇文章反复咀嚼我原来文章里提到的那篇《神经网络小实例》&#xff0c;大家可以先看看&#xff0c;比如做些环境准备等等&#xff08;这是我的这篇文章的链接&#xff09;&#xff1a; 政安晨的机器学习笔记——基于Anaconda安装TensorFlow并尝试一个神…

图像处理之《神经网络模型的通用隐写框架》论文阅读

一、文章摘要 在本文中&#xff0c;我们提出了一个通用的隐写框架&#xff0c;用于神经网络实现隐蔽通信。首先&#xff0c;我们设计了一种基线隐写方法&#xff0c;在网络训练过程中将秘密数据嵌入到给定神经网络(封面网络)的卷积层中。对于包含秘密数据的网络(隐写网络)&…

python 基础知识点(蓝桥杯python科目个人复习计划40)

今日复习内容&#xff1a;矩阵乘法&#xff0c;高斯消元 哈哈&#xff0c;我来干回老本行&#xff0c;复习点儿数学类专业学的东西 因为电脑上制作费时间&#xff0c;所以我直接用我的《高等代数》和《数值分析》笔记。 一.矩阵乘法 例题1&#xff1a;矩阵相乘 题目描述&am…