React Fiber源码分析 第一篇
先附上流程图一张

先由babel编译, 调用reactDOM.render,入参为element, container, callback, 打印出来可以看到element,container,callback分别代表着react元素、DOM原生元素,回调函数

render实际上调用的是 legacyRenderSubtreeIntoContainer函数
render: function (element, container, callback) {
return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
}
legacyRenderSubtreeIntoContainer 这个函数, 实际上是初始化了root, 并调用了root.render方法, 而root是由legacyCreateRootFromDOMContainer函数返回的
function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
var root = container._reactRootContainer;
if (!root) {
// 初始化root
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);// Initial mount should not be batched.
unbatchedUpdates(function () {
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
} else {
// 调用root的render方法
root.render(children, callback);
}
});
} else {
......
}
}
从代码中看出, legacyCreateRootFromDOMContainer执行了两个操作, 一个是清除掉所有的子元素, 另外一个则是返回了一个 ReactRoot实例, 这里需要注意一点, root默认是同步更新的, 即isAsync 默认为false
function legacyCreateRootFromDOMContainer(container, forceHydrate) {
...// 清除所有子元素
if (!shouldHydrate) {
var warned = false;
var rootSibling = void 0;
while (rootSibling = container.lastChild) {
{
if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) {
warned = true;
}
}
container.removeChild(rootSibling);
}
}// 默认为同步状态
var isAsync = false;
return new ReactRoot(container, isAsync, shouldHydrate);
}
从ReactRoot中, 我们把createContainer返回值赋给了 实例的_internalRoot, 往下看createContainer
function ReactRoot(container, isAsync, hydrate) {
var root = createContainer(container, isAsync, hydrate);
this._internalRoot = root;
}
从createContainer看出, createContainer实际上是直接返回了createFiberRoot, 而createFiberRoot则是通过createHostRootFiber函数的返回值uninitializedFiber,并将其赋值在root对象的current上, 这里需要注意一个点就是,uninitializedFiber的stateNode的值是root, 即他们互相引用
function createContainer(containerInfo, isAsync, hydrate) {
return createFiberRoot(containerInfo, isAsync, hydrate);
}
function createFiberRoot(containerInfo, isAsync, hydrate) {
// 创建hostRoot并赋值给uninitiallizedFiber
var uninitializedFiber = createHostRootFiber(isAsync);
// 互相引用
var root = void 0;
root = {
current: uninitializedFiber,
...
};
uninitializedFiber.stateNode = root;
最后是返回了一个fiberNode的实例, 在这里我们可以看到mode这个字段, 由于在一开始就将isAsync初始化为false, 所以mode实际上就代表了同步
在这里, 整理一下各个实例的关系,
root为ReactRoot实例,
root._internalRoot 即为fiberRoot实例,
root._internalRoot.current即为Fiber实例,
root._internalRoot.current.stateNode = root._internalRoot
function createHostRootFiber(isAsync) {
var mode = isAsync ? AsyncMode | StrictMode : NoContext;
return createFiber(HostRoot, null, null, mode);
}
var createFiber = function (tag, pendingProps, key, mode) {
return new FiberNode(tag, pendingProps, key, mode);
};
function FiberNode(tag, pendingProps, key, mode) {
// Instance
this.tag = tag;
this.key = key;
this.type = null;
this.stateNode = null;
// Fiber
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0;
...
}
初始化完成, 接下来就是root.render执行了, 在这里, 先暂时忽略ReactWork, 把work._onCommit当成一个回调函数即可, 可以看到, root即FiberRoot实例被当成参数传入了updateContsainer里面, 往下看updateContainer
ReactRoot.prototype.render = function (children, callback) {
var root = this._internalRoot;
var work = new ReactWork();
callback = callback === undefined ? null : callback;
if (callback !== null) {
work.then(callback);
}
updateContainer(children, root, null, work._onCommit);
return work;
};
updateContsainer里面使用了 currentTime 和 expirationTime,
currentTime是用来计算expirationTime,
expirationTime代表着优先级, 留在后续分析,
这里我们知道是同步更新 即 expirationTime = 1. 紧接着调用了updateContainerAtExpirationTime
function updateContainer(element, container, parentComponent, callback) {
var current$$1 = container.current;
var currentTime = requestCurrentTime();
var expirationTime = computeExpirationForFiber(currentTime, current$$1);
return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback);
}
updateContainerAtExpirationTime将current(即Fiber实例)提取出来, 并作为参数传入调用scheduleRootUpdate
function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) {
// TODO: If this is a nested container, this won't be the root.
var current$$1 = container.current;
...
return scheduleRootUpdate(current$$1, element, expirationTime, callback);
}
到了这里告一段落, scheduleRootUpdate接下来就是React新版本异步渲染的核心了, 留在下一篇继续解读
React Fiber源码分析 第一篇的更多相关文章
- React Fiber源码分析 第二篇(同步模式)
先附上两张流程图 1.scheduleRootUpdate 这个函数主要执行了两个操作 1个是创建更新createUpdate并放到更新队列enqueueUpdate, 1个是执行sheculeW ...
- React Fiber源码分析 (介绍)
写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...
- jrtplib源码分析 第一篇 jthread的编译与分析
第一篇 jthread的编译与分析 jrtplib代码依赖库jthread,因此先从jthread开始jrtplib的学习.首先从以下链接下载jthread的源代码http://research.ed ...
- React Fiber源码分析 第三篇(异步状态)
先附上流程图~ 调用setState时, 会调用classComponentUpdater的enqueueSetState方法, 同时将新的state作为payload参数传进 enqueueSetS ...
- linux0.11内核源码剖析:第一篇 内存管理、memory.c【转】
转自:http://www.cnblogs.com/v-July-v/archive/2011/01/06/1983695.html linux0.11内核源码剖析第一篇:memory.c July ...
- JUC源码分析-集合篇:并发类容器介绍
JUC源码分析-集合篇:并发类容器介绍 同步类容器是 线程安全 的,如 Vector.HashTable 等容器的同步功能都是由 Collections.synchronizedMap 等工厂方法去创 ...
- JUC源码分析-集合篇(十)LinkedTransferQueue
JUC源码分析-集合篇(十)LinkedTransferQueue LinkedTransferQueue(LTQ) 相比 BlockingQueue 更进一步,生产者会一直阻塞直到所添加到队列的元素 ...
- JUC源码分析-集合篇(九)SynchronousQueue
JUC源码分析-集合篇(九)SynchronousQueue SynchronousQueue 是一个同步阻塞队列,它的每个插入操作都要等待其他线程相应的移除操作,反之亦然.SynchronousQu ...
- JUC源码分析-集合篇(八)DelayQueue
JUC源码分析-集合篇(八)DelayQueue DelayQueue 是一个支持延时获取元素的无界阻塞队列.队列使用 PriorityQueue 来实现. 队列中的元素必须实现 Delayed 接口 ...
随机推荐
- navicat连接mysql出现2059错误
最近在学习django的时候需要用到数据库,于是便下载了navicat准备和mysql配套使用,但是在连接的时候确出现了如下问题: 网上查询过后,发现这个错误出现的原因是在mysql8之前的版本中加密 ...
- 《你不知道的JavaScript》三卷读后感
本系列的作者是Kyle Simpson,上卷译者赵望野.梁杰,中卷译者单业,下卷译者单业.姜南. 我个人觉得第一卷是本系列最好的(必读),而第二卷虽然也讲解了很多知识点,但是对于异步和性能的那部分提及 ...
- 30.Iterator
迭代对于我们搞Java的来说绝对不陌生.我们常常使用JDK提供的迭代接口进行Java集合的迭代. Iterator iterator = list.iterator(); while(iterator ...
- 手把手教你Chrome浏览器安装Postman(含下载云盘链接)【转载】
转载自:http://www.ljwit.com/archives/php/278.html 说明: Postman不多介绍,是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件.本文主要 ...
- Jenkins的初级应用(2)-Invoke Phing targets
Invoke Phing targets这个插件主要是读取xml形式包括自动化测试打包部署的配置文件,然后根据流程走下来.用phing命令读取并执行xml配置文件,然后执行定义的步骤.比如check. ...
- aaa配置(第十三组)
拓扑 网络情况 A PING B A PING C PC-B PING PC-C 2.R1的配置 a.console线 R1(config)#username admin1 password Admi ...
- 基于 Consul 实现 MagicOnion(GRpc) 服务注册与发现
0.简介 0.1 什么是 Consul Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置. 这里所谓的服务,不仅仅包括常用的 Api 这些服务,也包括软件开发过程 ...
- ionic2 基于ngx-translate实现多语言切换,翻译
介绍 ngx-translate 是Angular 2+的国际化(i18n)库,在github的地址是箭头 https://github.com/ngx-translate/core 将ngx-tra ...
- springBoot(10)---logback日志
logback日志 一.概述 和log4j优点: 实际上,这两个日志框架都出自同一个开发者之手,Logback 相对于 Log4J 有更多的优点 (1)logback不仅性能提升了,初始化内存加载也 ...
- Go语言下的线程模型
阅读Go并发编程对go语言线程模型的笔记,解释的非常到,好记性不如烂笔头,忘记的时候回来翻一番,在此做下笔记. Go语言的线程实现模型,又3个必知的核心元素,他们支撑起了这个线程实现模型的主要框架: ...