react.js源码二
三、调度Scheduler
scheduling(调度)是fiber reconciliation的一个过程,主要决定应该在何时做什么?在stack reconciler中,reconciliation是“一气呵成”,对于函数来说,这没什么问题,因为我们只想要函数的运行结果,但对于UI来说还需要考虑以下问题:
并不是所有的state更新都需要立即显示出来,比如屏幕之外的部分的更新;
并不是所有的更新优先级都是一样的,比如用户输入的响应优先级要比通过请求填充内容的响应优先级更高;
理想情况下,对于某些高优先级的操作,应该是可以打断低优先级的操作执行的,比如用户输入时,页面的某个评论还在reconciliation,应该优先响应用户输入。
比如18版本里concurrent 模式 (默认情况下未启用) 提示一些不安全的生命周期主要是它被打断了可能会被执行多次。如:
- componentWillMount (or UNSAFE_componentWillMount)
- componentWillReceiveProps (or UNSAFE_componentWillReceiveProps)
- componentWillUpdate (or UNSAFE_componentWillUpdate)
所以不要在它们内部编写副作用相关的代码,严格模式不能自动检测到你的副作用,但它可以帮助你发现它们。严格模式每当第一次安装组件时,这个新的检查将自动卸载并重新安装每个组件,并在第二次挂载时恢复之前的 state,这样可以检测你的代码载销毁时是否清除副作用。严格模式仅适用于开发模式。生产模式下生命周期不会被调用两次。
所以理想状况下reconciliation的过程应该是每次只做一个很小的任务,做完后能够“喘口气儿”,回到主线程看下有没有什么更高优先级的任务需要处理,如果有则先处理更高优先级的任务,没有则继续执行(cooperative scheduling 合作式调度)。
当用户操作时,调用setState,react会把当前的更新送入对应组件对应的update queue中。但是react并不会立即执行对比并修改DOM的操作。而是交给scheduler去处理。
scheduler会根据当前主线程的使用情况去处理这次update。为了实现这种特性,最开始考虑使用了requestIdelCallback API。
总的来讲,通常,客户端线程执行任务时会以帧的形式划分,大部分设备控制在30-60帧是不会影响用户体验;在两个执行帧之间,主线程通常会有一小段空闲时间,requestIdleCallback可以在这个空闲期(Idle Period)调用空闲期回调(Idle Callback),执行一些任务。
低优先级任务由requestIdleCallback处理;
高优先级任务,如动画相关的由requestAnimationFrame处理;
requestIdleCallback可以在多个空闲期调用空闲期回调,执行任务;
requestIdleCallback方法提供deadline,即任务执行限制时间,以切分任务,避免长时间执行,阻塞UI渲染而导致掉帧;
但是由于requestIdleCallback有以下两个问题就采用了messageChannel模拟实现了requestIdleCallback。
1)兼容性;
2)50ms 渲染问题;(可能在一些任务很长时这个回调不会执行)
|— task queue —|— micro task —|— raf —|— render —|— requestIdleCallback – -|
requestIdleCallback是宏任务,messageChannel也宏任务。
为什么没有⽤ generator ?因为它是有状态的,无法从中间中断。
为什么没有⽤ setTimeout ?因为setTimeout有4-5ms的延时。
模拟了requestIdleCallback行为:
/*** schedule —> 把我的任务放进一个队列里,然后以某一种节奏进行执行;* */// task 的任务队列
const queue = [];
const threshold = 1000 / 60;const transtions = [];
let deadline = 0;// 获取当前时间, bi date-now 精确
const now = () => performance.now(); // 时间 ,精确
// 从任务queue中,选择第一个 任务
const peek = arr => arr.length === 0 ? null : arr[0];// schedule —> 把我的任务放进一个队列里,然后以某一种节奏进行执行;
export function schedule (cb) {queue.push(cb);startTranstion(flush);
}// 此时,是否应该交出执行权
function shouldYield() {return navigator.scheduling.isInputPending() || now() >= deadline;
}// 执行权的切换
function startTranstion(cb) {transtions.push(cb) && postMessage();
}// 执行权的切换
const postMessage = (() => {const cb = () => transtions.splice(0, 1).forEach(c => c());const { port1, port2 } = new MessageChannel();port1.onmessage = cb;return () => port2.postMessage(null);
})()// 模拟实现 requestIdleCallback 方法
function flush() {// 生成时间,用于判断deadline = now() + threshold;let task = peek(queue);// 我还没有超出 16.666ms 同时,也没有更高的优先级打断我while(task && !shouldYield()) {const { cb } = task;const next = cb();// 相当于有一个约定,如果,你这个task 返回的是一个函数,那下一次,就从你这里接着跑// 那如果 task 返回的不是函数,说明已经跑完了。不需要再从你这里跑了if(next && typeof next === "function") {task.cb = next;} else {queue.shift()}task = peek(queue);}// 如果我的这一个时间片,执行完了,到了这里。task && startTranstion(flush)
}
一旦reconciliation过程得到时间片,就开始进入work loop。work loop机制可以让react在计算状态和等待状态之间进行切换。为了达到这个目的,对于每个loop而言,需要追踪两个东西:下一个工作单元(下一个待处理的fiber);当前还能占用主线程的时间。第一个loop,下一个待处理单元为根节点。
每个工作单元(fiber)执行完成后,都会查看是否还继续拥有主线程时间片,如果有继续下一个,如果没有则先处理其他高优先级事务,等主线程空闲下来继续执行
react17版本有时间切片ric,但是没有使用。18版本里才使用了。
宏任务微任务执行示例
四、diff算法
react diff算法最好时是O(n), 最差的话,是 O(mn),而传统的diff算法是O(n^3)。
react 是如何将 diff 算法的复杂度降下来的?
其实就是在算法复杂度、虚拟 dom 渲染机制、性能中找了⼀个平衡,react 采⽤了启发式的算法,做了如下最优假设:
a. 如果节点类型相同,那么以该节点为根节点的 tree 结构,⼤概率是相同的,所以如果类型不同,可以直接「删除」原节点,「插⼊」新节点;
b. 跨层级移动⼦ tree 结构的情况⽐较少⻅,或者可以培养⽤户使⽤习惯来规避这种情况,遇到这种情况同样是采⽤先「删除」再「插⼊」的⽅式,这样就避免了跨层级移动
c. 同⼀层级的⼦元素,可以通过 key 来缓存实例,然后根据算法采取「插⼊」「删除」「移动」的操作,尽量复⽤,减少性能开销
d. 完全相同的节点,其虚拟 dom 也是完全⼀致的;
react为什么不去优化diff算法?
因为新版本下,diff算法不是约束性能瓶颈的问题了。
为什么要有key?
在⽐较时,会以 key 和 type 是否相同进⾏⽐较,如果相同,则直接复制
vue diff算法和react diff算法相同/不同点:
共同点:
vue和diff算法,都是不进行跨层级比较,只做同级比较
不同点:
1.vue进行diff时,调用patch打补丁函数,一边比较一边给真实的dom打补丁,vue对比节点时,当节点元素类型相同,类名不同时,认为是不同的元素,删除重新创建,而react认为是同类型的节点,进行修改操作
2.vue列表对比的时候,采用从两端到中间的方式,旧集合和新集合两端各存在两个指针,两两进行比较,每次对比结束后,指针向队列中间移动;react则是从左往右一次对比,利用元素的index和lastindex进行比较
3.当一个集合把最后一个节点移动到最前面,react会把前面的节点依次向后移动,而Vue只会把最后一个节点放在最前面,这样的操作来看,Vue的diff性能是高于react的。
四、模拟实现react流程
react.js
const normalize = (children = []) => children.map(child => typeof child === 'string' ? createVText(child): child)export const NODE_FLAG = {EL: 1, // 元素 element
相关文章:
react.js源码二
三、调度Scheduler scheduling(调度)是fiber reconciliation的一个过程,主要决定应该在何时做什么?在stack reconciler中,reconciliation是“一气呵成”,对于函数来说,这没什么问题,因为我们只想要函数的运行结果,但对于UI来说还需要考虑以下问题: 并不是所有的state更…...
如何学习英语
前言 首先写一些自己的感言吧,其实从大学的时候就在不断地听英语,学英语,但是到毕业十几年后,英语一直没起到什么作用,当然最有作用的时候就是几次英语面试吧。 工作之后有一段学习英语的经历,当时花费了…...
robot测试自动化
一. 安装 黑羽robot 首先确保你电脑上安装好了 Python 3.7 或者 3.8 版本的解释器 hyrobot 使用说明1 | 白月黑羽 安装RF 黑羽robot基于Robot Framework ,所以必须先安装RobotFramework 直接执行如下Pip命令即可: pip install robotframework...
Linux---重定向命令
1. 重定向命令的介绍 重定向也称为输出重定向,把在终端执行命令的结果保存到目标文件。 2. 重定向命令的使用 命令说明>如果文件存在会覆盖原有文件内容,相当于文件操作中的‘w’模式>>如果文件存在会追加写入文件末尾,相当于文件…...
小区生活污水处理需要哪些设备和工艺
在小区生活中,污水处理是一个非常重要的环节,它关乎到环境的保护和居民的生活质量。因此,了解小区生活污水处理所需要的设备和工艺是至关重要的。 首先,在小区生活污水处理中,需要用到的设备包括污水收集系统、初级沉淀…...
【高性能计算】Cpp + Eigen + Intel MKL + 函数写成传引用
CUDA加速原理:CUDA编程学习:自定义Pytorch+cpp/cuda extension 高质量C++进阶[2]:如何让线性代数加速1000倍? 【gcc, cmake, eigen, opencv,ubuntu】三.eigen和mkl安装和使用 Linux下MKL库的安装部署与使用,并利用cmake编译器调用MKL库去提升eigen库的计算速度 Eigen库…...
【教学类-05-02】20231216 (比大小> <=)X-Y之间的比大小88题(补全88格子,有空格分割提示)
作品展示: 背景需求: 1、以前做过一份比大小的题目 【教学类-05-01】20211018 Python VSC 大班 数字比大小(> <)_vsc比较3位数大小-CSDN博客文章浏览阅读674次。【教学类-05-01】20211018 Python VSC 大班…...
【Spark精讲】Spark与MapReduce对比
目录 对比总结 MapReduce流程 编辑 MapTask流程 ReduceTask流程 MapReduce原理 阶段划分 Map shuffle Partition Collector Sort Spill Merge Reduce shuffle Copy Merge Sort 对比总结 Map端读取文件:都是需要通过split概念来进行逻辑切片&…...
SQL错题集3
1.薪水第二多的员工的emp_no以及其对应的薪水salary limit a,b 其中a表示查询数据的起始位置,b表示返回的数量。 (MySQL数据库中的记录是从0开始的) 注意从0开始 2.员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth 聚合函数不能…...
Elasticsearch:使用 OpenAI 生成嵌入并进行向量搜索 - nodejs
在我之前的文章: Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (一)(二)(三)(四) 我详细地描述了如何使用…...
[python高级编程]:02-类
此系列主要用于记录Python学习过程中查阅的优秀文章,均为索引方式。其中内容只针对本作者一人,作者熟悉了解的内容不再重复记录。 目录 01-装饰器 overload -- 方法重载 02-多态 多态和鸭子类型 03-设计模式 抽象基类和接口 01-装饰器 overload -- 方…...
java.lang.UnsupportedOperationException异常解决
在执行如下代码时,发现当apps.add("...");代码执行时,会报java.lang.UnsupportedOperationException错误 List<String> apps Arrays.asList("...");apps.add("..."); 问题出现的原因如下: 1、ArrayLi…...
openmediavault debian linux安装配置企业私有网盘(三 )——raid5与btrfs文件系统无损原数据扩容
一、适用环境 1、企业自有物理专业服务器,一些敏感数据不外流时,使用openmediavault自建NAS系统; 2、在虚拟化环境中自建NAS系统,用于内网办公,或出差外网办公时,企业内的文件共享; 3、虚拟化环…...
Two Phase Termination(两阶段)设计模式
Two Phase Termination设计模式是针对任务由两个环节组成,第一个环节是处理业务相关的内容,第二个阶段是处理任务结束时的同步、释放资源等操作。在进行两阶段终结的时候,需要考虑: 第二阶段终止操作必须保证线程安全。 要百分百…...
闲人闲谈PS之四十九——PLM和SAP集成常见的问题
惯例闲话:天气突变,没想到珠三角也骤降了10几度,昨晚还吹风扇模式,早上起来一下子感觉丝丝凉意。闲人还是喜欢冬天,冷,能让人思维清晰,提高工作效率。趁着天气适宜,赶紧加班擦屁股去…...
帆软BI目录
数据导入ORACLE库 写法 SELECT * FROM (SELECT a.id ,a.expandType,a.parentId,a.displayName,a.sortIndex,LEVEL lv ,replace(sys_connect_by_path(displayName,//),//Dec-Entry_Management//,) AS 路径FROM FINE_AUTHORITY_OBJECT aSTART WITH a.id decision-directory-ro…...
(第8天)保姆级 PL/SQL Developer 安装与配置
PL/SQL Developer 安装与配置(第8天) 咱们前面分享了很多 Oracle 数据库的安装,但是还没有正式使用过 Oracle 数据库,怎么连接 Oracle 数据库?今天就来讲讲我学习中比较常用的 Oracle 数据库连接工具:PL/SQL DEVELOPER。 PL/SQL Developer 的安装和配置对于新手来说还是…...
【CSS】前端点点点加载小点样式css动画过程实现
对话的 ... 加载动画,直接用 CSS 就可以实现,样式可以自己改,逻辑大差不差 <div class"loading-text"><span class"dot1"></span><span class"dot2"></span><span class&quo…...
【LeetCode: 2415. 反转二叉树的奇数层 | BFS + DFS】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...
期货股市联动(期股联动助推资本市场上扬)
期股联动——期货股市助推资本市场上扬 随着我国资本市场的不断发展,期货和股票这两个市场也在逐渐紧密地联系起来。期货和股票的相互作用是一种“期股联动”,它能够促进资本市场的上扬。 期货与股票市场 期货市场是一种标准化的场外交易市场…...
生成式AI的力量,释放RPA的无限潜能
回首即将过去的2023年,互联网行业似乎始终处在各种新概念的热潮激荡之中。其中,最引人注目的话题无疑是AI科技。自人工智能技术实现大规模突破以来,我们见证了一系列生成式AI的涌现。从ChatGPT到百度文心一言,它们纷纷登场&#x…...
【leetcode】链表总结
说明:本文内容来自于代码随想录 链表基本操作 https://leetcode.cn/problems/design-linked-list/ 删除节点 https://leetcode.cn/problems/remove-linked-list-elements/description/,删除节点,虚拟头节点。定义两个节点,分别…...
焦虑,其实是你自愿选择的
如果一个人想要焦虑,他可以永远焦虑下去 从上学,到找工作,从买房到结婚生娃,他总是可以选择用自己的头脑去过度思考未来还没有发生的事情,从而让自己无限焦虑下去,直到生命终结。 我们的生命是存在于当下…...
4G无线工业级路由器在智能制造设备互联互通中的角色
随着工业技术的不断发展和进步,智能制造已经成为了现代制造业的重要趋势和发展方向。而在智能制造过程中,设备之间的互联互通是至关重要的一环。在这个过程中,4G无线工业级路由器扮演着重要的角色,它提供了稳定可靠的网络连接&…...
gitbash下载安装
参考教程 零、下载 官网地址 2.43.0win64 链接:https://pan.baidu.com/s/16urs_nmky7j20-qNzUTTkg 提取码:7jaq 一、安装 图标组件(Additional icons):选择是否创建桌面快捷方式;桌面浏览(Win…...
系列一、Linux中安装MySQL
一、Linux中安装MySQL 1.1、下载MySQL安装包 官网:https://dev.mysql.com/downloads/file/?id523327 我分享的: 链接:https://pan.baidu.com/s/188_9RnBYlWVzFb_UJH5aaQ?pwdyyds 提取码:yyds 1.2、上传至/opt目录 & 解压…...
开辟“护眼绿洲”,荣耀何以为师?
文 | 智能相对论 作者 | 佘凯文 俗话说,眼睛是心灵的窗户,可如今,人们对于这扇“窗户”的保护,似乎越来越不重视。 据人民日报今年发布的调查显示,中国眼病患病人数2.1亿,近视患者人数多达6亿࿰…...
Modbus RTU和Modbus TCP的区别 深入篇
目录 1 传输方式不同 2 硬件接口不同 3 校验码不同 4 指令内容不同 4.1 Modbus RTU 4.1.1 功能码为03,表示读寄存器 4.1.2 功能码为10,表示写多个寄存器 4.2 Modbus TCP 4.2.1 功能码为03,表示读寄存器 4.2.2 回复异常报文 5 传输速…...
【大数据】Doris 的集群规划和环境准备
Doris 的集群规划和环境准备 1.1 环境要求1.1 Linux 操作系统版本需求1.2 软件需求 1.2 硬件要求1.3 节点规划1.4 通信端口1.5 IP 地址绑定 Doris 作为一款开源的 MPP 架构 OLAP 数据库,能够运行在绝大多数主流的商用服务器上。为了能够充分运用 MPP 架构的并发优势…...
connect: Network is unreachable问题解决
第一步:查看ifcfg-ens33配置文件 cd /etc/sysconfig/network-scripts/ cat ifcfg-ens33 发现问题:GATEWAY写错成GATWAY 第二步:修改 vim ifcfg-ens33 第三步:检测是否成功 ping baidu.com 成功!...
go.php wordpress/今日国内新闻头条
Billu_b0x 靶机 write up0x00 环境搭建0x01 信息收集0x02 漏洞挖掘0x03 获取shell0x04 提权0x05 思路总结0x00 环境搭建 下载链接 https://download.vulnhub.com/billu/Billu_b0x.zipnat模式 0x01 信息收集 IP探测 netdiscover -i eth0 -r 192.168.157.0/24 端口探测 mass…...
三六五网做网站吗/免费网站模板
作为局域网的主要连接设备,以太网交换机成为应用普及最快的网络设备之一,同时,也是随着这种快速的发展,交换机的功能不断增强,随之而来则是交换机端口的更新换代以及各种特殊设备连接端口不断的添加到交换机上…...
找人做网站需要准备什么材料/济南今日头条新闻
删除软件要删除软件非常简单,只要执行下面的命令就行:# rpm –e xanim这时,用户要注意使用的是软件的名称xanim,而不是软件包的名称xanim-27.64-3.i386.rpm。如果要删除的软件是其它软件所需要的,用户会得到类似下面…...
公司做网站多/搜索引擎优化方法有哪些
作者:瀚高PG实验室 (Highgo PG Lab)- 波罗 autovacuum 是 postgresql 里非常重要的一个服务端进程,能够自动地执行,在一定条件下自动地对 dead tuples 进行清理并对表进行分析 autovacuum参数控制 autovacuum 进程是…...
搭建一个网站需要多久/自媒体平台大全
1.Mi 快传 https://www.lanzous.com/i69ty9c 2.快牙(跨平台) https://www.lanzous.com/i69tybe 3.Mi互传(Win10(verson>1903)) http://lanzous.com/i6wiuef 4.百灵快传(跨平台-有二进制包) 基于Go https://github.com/bitepeng/b0pass 国内可以到介绍的gitee地址直接…...
网站抢购外挂软件怎么做/网站开发流程有哪几个阶段
解析如何屏蔽php中的phpinfo()函数我们配置php环境的时候往往都会写phpinfo();这个函数来测试php环境是否安装成功,但往往这个函数也会给系统带来安全隐患,那么如何让关掉这个函数呢?下面介绍一种方法:修改php.ini文件…...