React16源码: React中的resetChildExpirationTime的源码实现

本文主要是介绍React16源码: React中的resetChildExpirationTime的源码实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

resetChildExpirationTime


1 )概述

  • completeUnitOfWork 当中,有一步比较重要的一个操作,就是重置 childExpirationTime
  • childExpirationTime 是非常重要的一个时间节点,它用来记录某一个节点的子树当中,目前优先级最高的那个更新
  • 整个应用的调度过程当中使用的都是root节点,在 scheduleWork 的时候,即便我们创建更新的那个节点,是我们写的某一个组件
  • 但最终要先找到那一个root节点,然后再把它放到调度队列当中,因为会有这样的一个情况的存在
  • 所以我们对于一个 reactApp 来说,它某一个节点下面可能是会存在非常多的一个子树的
  • 每棵子树它创建的不同的任务,它的 expirationTime 都会不一样的
  • 通过 childExpirationTime 来集中,最终可以在 root 上面能够快速的找到整个应用当中优先级最高的那个任务
  • 举个例子,假设同时在 Input 和 List 两个组件内都去创建了一个异步的更新,创建这个异步的更新的过程当中
  • 假设,Input的 ExpirationTime 优先级比较高,List 的 expirationTime 优先级比较少
  • 对于div节点来说,它记录的是Input节点的 expirationTime, 因为它的优先级比较高
  • 对于div来说,它如果下一个任务要去更新,它的优先级肯定是先更新 Input,而不会先更新 List
  • 对于 RootFiber 和 App来说,因为它们的child只有div, 所以它们记录的会是 div 上面指定的那个优先级最高的 expirationTime
  • 所以说 childExpirationTime 对于有分叉的点来说是非常重要的, 它可以记录不同的子树所创建的不同的更新
  • 如果我们的分叉变得越来越多,有非常多个的时候,那么用这种方式来记录它的效率明显是会是更高一点的
  • 对于这个情况下,如果我 Input 这个更新已经执行完了,它上面已经没有 expirationTime,因为它没有任务要去更新了
  • 对于div来说,这个时候如果它还是认为这个Input它之前的 expirationTime 是最高优先级的话,那就不对了,之后的更新可能就会有出现问题
  • 所以对于div这个节点,我们执行了 completeUnitOfWork 之后,要去更新它的 childExpirationTime
  • 对于每一个节点都是一样的, 在上述这个例子里面,特别重要的一点就是 div, div 要更新,那么它上面的节点都是要更新的
  • 因为它们之前记录的都是 div 记录的那个值,所以,它们执行 completeUnitOfWork 的时候,也都要去做相同的操作

2 )源码

定位到 packages/react-reconciler/src/ReactFiberScheduler.js#L989

对应到代码里面,来看在 completeUnitOfWork 里面,我们这边执行完了 completeWork
马上会执行 resetChildExpirationTime 那么这个方法它具体做了什么呢?

function resetChildExpirationTime(workInProgress: Fiber,renderTime: ExpirationTime,
) {// 首先判断 renderTime ,就是当前正在执行更新的那一个优先级对应的 expirationTime// 如果它不等于never,并且 workInProgress.childExpirationTime 等于 Never// 也就是说 workInProgress 就是我们当前节点的子节点优先级最高的那个任务是never// 就是永远不会更新到的并且我们现在也不是正在执行,never,就是永远不会更新到的那些节点的更新// 说明我们这边根本就不需要做任何的操作,所以我们直接return就可以了if (renderTime !== Never && workInProgress.childExpirationTime === Never) {// The children of this component are hidden. Don't bubble their// expiration times.return;}let newChildExpirationTime = NoWork;// Bubble up the earliest expiration time.// 跳过这个if, 直接到 elseif (enableProfilerTimer && workInProgress.mode & ProfileMode) {// We're in profiling mode.// Let's use this same traversal to update the render durations.let actualDuration = workInProgress.actualDuration;let treeBaseDuration = workInProgress.selfBaseDuration;// When a fiber is cloned, its actualDuration is reset to 0.// This value will only be updated if work is done on the fiber (i.e. it doesn't bailout).// When work is done, it should bubble to the parent's actualDuration.// If the fiber has not been cloned though, (meaning no work was done),// Then this value will reflect the amount of time spent working on a previous render.// In that case it should not bubble.// We determine whether it was cloned by comparing the child pointer.const shouldBubbleActualDurations =workInProgress.alternate === null ||workInProgress.child !== workInProgress.alternate.child;let child = workInProgress.child;while (child !== null) {const childUpdateExpirationTime = child.expirationTime;const childChildExpirationTime = child.childExpirationTime;if (childUpdateExpirationTime > newChildExpirationTime) {newChildExpirationTime = childUpdateExpirationTime;}if (childChildExpirationTime > newChildExpirationTime) {newChildExpirationTime = childChildExpirationTime;}if (shouldBubbleActualDurations) {actualDuration += child.actualDuration;}treeBaseDuration += child.treeBaseDuration;child = child.sibling;}workInProgress.actualDuration = actualDuration;workInProgress.treeBaseDuration = treeBaseDuration;} else {// 这边主要是有一个 while循环, 这个while循环它首先使用的是 workInProgress.child// 它就是我们当前节点的child,然后获取child的 expirationTime 以及 childChildExpirationTime// child.expirationTime 是它自身它所创建的更新对应的 expirationTime// 而 child.childExpirationTime 是child的子树里面任何几个节点它所创建的更新所对应的优先级最高的 expirationTimelet child = workInProgress.child;while (child !== null) {// 为什么这边要用这两个值?因为我们没有办法直接拿到当前节点它所有子树最高优先级的点// 只能是通过去遍历它的所有的第一层的子节点以及每个子节点它的 childExpirationTime// 因为我们这个 completeUnitOfWork 是由底往上去更新的一个过程// 那么由底往上更新的过程,就会每一个节点都会对应这个操作// 对应的这个操作之后,它肯定就是每一个节点都会更新到优先级最高的那个 expirationTimeconst childUpdateExpirationTime = child.expirationTime;const childChildExpirationTime = child.childExpirationTime;// 接下来进行判断更新if (childUpdateExpirationTime > newChildExpirationTime) {newChildExpirationTime = childUpdateExpirationTime;}if (childChildExpirationTime > newChildExpirationTime) {newChildExpirationTime = childChildExpirationTime;}// 下一个节点child = child.sibling;}}workInProgress.childExpirationTime = newChildExpirationTime;
}
  • 以上注释写在代码里,简单来说
    • 就是在每一次 complete 一个节点之后就要
    • 去重设它的 childExpirationTime 的一个过程

这篇关于React16源码: React中的resetChildExpirationTime的源码实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/634999

相关文章

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

python中列表list切分的实现

《python中列表list切分的实现》列表是Python中最常用的数据结构之一,经常需要对列表进行切分操作,本文主要介绍了python中列表list切分的实现,文中通过示例代码介绍的非常详细,对大家... 目录一、列表切片的基本用法1.1 基本切片操作1.2 切片的负索引1.3 切片的省略二、列表切分的高

基于Python实现一个PDF特殊字体提取工具

《基于Python实现一个PDF特殊字体提取工具》在PDF文档处理场景中,我们常常需要针对特定格式的文本内容进行提取分析,本文介绍的PDF特殊字体提取器是一款基于Python开发的桌面应用程序感兴趣的... 目录一、应用背景与功能概述二、技术架构与核心组件2.1 技术选型2.2 系统架构三、核心功能实现解析

使用Python实现表格字段智能去重

《使用Python实现表格字段智能去重》在数据分析和处理过程中,数据清洗是一个至关重要的步骤,其中字段去重是一个常见且关键的任务,下面我们看看如何使用Python进行表格字段智能去重吧... 目录一、引言二、数据重复问题的常见场景与影响三、python在数据清洗中的优势四、基于Python的表格字段智能去重

Spring AI集成DeepSeek实现流式输出的操作方法

《SpringAI集成DeepSeek实现流式输出的操作方法》本文介绍了如何在SpringBoot中使用Sse(Server-SentEvents)技术实现流式输出,后端使用SpringMVC中的S... 目录一、后端代码二、前端代码三、运行项目小天有话说题外话参考资料前面一篇文章我们实现了《Spring

Nginx中location实现多条件匹配的方法详解

《Nginx中location实现多条件匹配的方法详解》在Nginx中,location指令用于匹配请求的URI,虽然location本身是基于单一匹配规则的,但可以通过多种方式实现多个条件的匹配逻辑... 目录1. 概述2. 实现多条件匹配的方式2.1 使用多个 location 块2.2 使用正则表达式

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

SpringBoot实现导出复杂对象到Excel文件

《SpringBoot实现导出复杂对象到Excel文件》这篇文章主要为大家详细介绍了如何使用Hutool和EasyExcel两种方式来实现在SpringBoot项目中导出复杂对象到Excel文件,需要... 在Spring Boot项目中导出复杂对象到Excel文件,可以利用Hutool或EasyExcel

前端bug调试的方法技巧及常见错误

《前端bug调试的方法技巧及常见错误》:本文主要介绍编程中常见的报错和Bug,以及调试的重要性,调试的基本流程是通过缩小范围来定位问题,并给出了推测法、删除代码法、console调试和debugg... 目录调试基本流程调试方法排查bug的两大技巧如何看控制台报错前端常见错误取值调用报错资源引入错误解析错误

Python如何实现读取csv文件时忽略文件的编码格式

《Python如何实现读取csv文件时忽略文件的编码格式》我们再日常读取csv文件的时候经常会发现csv文件的格式有多种,所以这篇文章为大家介绍了Python如何实现读取csv文件时忽略文件的编码格式... 目录1、背景介绍2、库的安装3、核心代码4、完整代码1、背景介绍我们再日常读取csv文件的时候经常