【React】1077- React Fiber架构浅析
1.浏览器渲染
为了更好的理解 React Fiber, 我们先简单了解下渲染器进程的内部工作原理。
参考资料:
从内部了解现代浏览器(3)[1]
渲染树构建、布局及绘制[2]
1.1 渲染帧
帧 (frame): 动画过程中,每一幅静止的画面叫做帧。
帧率 (frame per second): 即每秒钟播放的静止画面的数量。
帧时长 (frame running time): 每一幅静止的画面的停留时间。
丢帧 (dropped frame): 当某一帧时长高于平均帧时长。
一般来说浏览器刷新率在60Hz, 渲染一帧时长必须控制在16.67ms (1s / 60 = 16.67ms)。
如果渲染超过该时间, 对用户视觉上来说,会出现卡顿现象,即丢帧 (dropped frame)。
1.2 帧生命周期
图: 简单描述帧生命周期
简单描述一帧的生命周期:1. 一帧开始。2. 主线程:- Event Handlers: UI交互输入的事件回调, 例如input、click、wheel等。- RAF: 执行requestAnimationFrame回调。- DOM Tree: 解析HTML, 构建DOM Tree, 当JS对DOM有变更会重新触发该流程。- CSS Tree: 构建CSS Tree。至此构建出Render Tree。- Layout: 所有元素的position、size信息。- Paint: 像素填充, 例如颜色、文字、边框等可视部分。- Composite: 绘制的指令信息传到合成线程中。- RequestIdleCallback: 如果此时一帧还有空余时间, 则执行该回调。3. 合成线程:- Raster: 合成线程将信息分块, 并把每块发送给光栅线程, 光栅线程创建位图, 并通知GPU进程刷新这一帧。4. 一帧结束。
1.3 丢帧实验
怎么就丢帧了呢?
对于流畅的动画,如果一帧处理时间超过16ms,就能感到页面的卡顿了。
Demo: https://linjiayu6.github.io/FE-RequestIdleCallback-demo/
Github: RequestIdleCallback 实验[3]
当用户点击任一按键 A,B,C,因为主线程执行Event Handlers任务,动画因为浏览器不能及时处理下一帧,导致动画出现卡顿的现象。
// 处理同步任务,并占用主线程const bindClick = id => element(id).addEventListener('click', Work.onSyncUnit)// 绑定click事件bindClick('btnA')bindClick('btnB')bindClick('btnC')var Work = {// 有1万个任务unit: 10000,// 处理每个任务onOneUnit: function () { for (var i = 0; i <= 500000; i++) {} },// 同步处理: 一次处理完所有任务onSyncUnit: function () {let _u = 0while (_u < Work.unit) {Work.onOneUnit()_u ++}}}
1.4 解决丢帧
上述,我们发现 JS运算是占用渲染的时间的。
在连续动画中,要做高耗时的操作,如何保证帧平稳呢?
解决丢帧思考如下:
一帧空闲时处理, 利用 RequestIdleCallback[4] 处理任务。
window.requestIdleCallback()方法将在浏览器的空闲时段内调用的函数排队。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout,则有可能为了在超时前执行函数而打乱执行顺序。
对高耗时的任务,进行分步骤处理。
Web worker 貌似也可以解决上述问题,这里不做扩展。
...
这里我们利用 RequestIdleCallback[5] 做个实验咩。
Demo: https://linjiayu6.github.io/FE-RequestIdleCallback-demo/
Github: RequestIdleCallback 实验
const bindClick = id => element(id).addEventListener('click', Work.onAsyncUnit)// 绑定click事件bindClick('btnA')bindClick('btnB')bindClick('btnC')var Work = {// 有1万个任务unit: 10000,// 处理每个任务onOneUnit: function () { for (var i = 0; i <= 500000; i++) {} },// 异步处理onAsyncUnit: function () {// 空闲时间 1msconst FREE_TIME = 1let _u = 0function cb(deadline) {// 当任务还没有被处理完 & 一帧还有的空闲时间 > 1mswhile (_u < Work.unit && deadline.timeRemaining() > FREE_TIME) {Work.onOneUnit()_u ++}// 任务干完, 执行回调if (_u >= Work.unit) {// 执行回调return}// 任务没完成, 继续等空闲执行window.requestIdleCallback(cb)}window.requestIdleCallback(cb)}}
requestIdleCallback 启发
将一个大任务分割成N个小任务,在每一帧有空余时间情况下,逐步去执行小任务。
2.React15 (-) 架构缺点
React: stack reconciler实现[7]
React 算法之深度优先遍历[8]
递归 Recursion: 利用 调用栈[9],实现自己调用自己的方法。
最常见的就是 Leetcode: 斐波拉契数列[10] 、Leetcode: 70. 爬楼梯[11]。
2.1 概述原因
该情况,类似我们上述# 1.3丢帧实验。
2.2 流程和代码解析
可能需要你有点 深度优先遍历、递归、回溯思想、???? 等数据结构的知识。
这里只做流程解析,代码也为阉割版,重点是理解思想哈。
某React节点如下:
class A extends React.Component {...render() {return (<div id="app"><h1></h1><p><h2></h2></p><h3></h3></div>)}}
图 DFS + 递归遍历的路径
下面是 ReactFiberWorkLoop.old.js[12] 阉割版代码,为了简要说明该流程。
// 工作循环同步处理function workLoopSync() {// 有任务while (workInProgress !== null) {performUnitOfWork(workInProgress);}}function performUnitOfWork(unitOfWork: Fiber): void {// 对该节点 开始工作: return workInProgress.child; 返回的是该节点的孩子let next = beginWork(...);if (next === null) {// 对某Node 完成工作: 回溯向上, 向上找到某节点的兄弟 sibling 或 直到向上为root代表, 遍历结束。completeUnitOfWork(unitOfWork);} else {// 从ta 孩子入手, 继续向下工作workInProgress = next;}}/*** siblingFiber: 兄弟节点* returnFiber: 父亲节点*/function completeUnitOfWork(unitOfWork: Fiber): void {let completedWork = unitOfWork;// 这里又是一个循环do {// 1. 判断任务是否完成, 完成就打个完成的标签, 没有完成就抛出异常// 2. 如果有兄弟节点, 那么接下来工作节点是该 xdif (completedWork.sibling !== null) {workInProgress = siblingFiber;return;}// 3. 否则, 返回父亲节点completedWork = completedWork.return;workInProgress = completedWork;} while (completedWork !== null);// 最后, 是root节点, 结束if (workInProgressRootExitStatus === RootIncomplete) {workInProgressRootExitStatus = RootCompleted;}}
3.上述总结
因果关系
基于这些原因,React不得不重构整个框架。
1. React (15ver-) 对创建和更新节点的处理,是通过 递归 ????。2. 递归 , 在未完成对整个???? 的遍历前,是不会停止的。3. 该 任务 一直占用浏览器主线程,导致无 响应优先级更高 的任务。4. 故,浏览器渲染超过临界时间,从视觉上来看,卡死 ????。
主动思考
为了快速响应,防止丢帧,解决思路:1. 将 任务 分解成 N个小任务;2. If 一帧里没有 优先级更高的任务,则执行自己。else 有其他 优先级高的事务, 优先执行其他。If 等一帧有 空闲 再执行自己。else 下一帧。
我们再回头看下这个图,问题即转换如下:
如何将任务拆分?如何判断优先级?如何判断一帧空闲时,再执行?...
Fiber 架构
推荐 ???? https://github.com/7kms/react-illustration-series/tree/v17.0.1
推荐 ???? https://react.iamkasong.com/preparation/oldConstructure.html
下面,不会有大段大段代码,去讲具体的实现。
而是,以因果逻辑,带你去了解 why,how,when (为什么、怎么做、何时做)。
4.抽象问题
上面我们说到了什么任务、优先级等等,我们通过图的方式,抽象下问题。
描述:1. 任务A进入执行区域。2. 在执行任务A的过程中,更高优先级任务B,请求被执行。3. 但因为先来后到嘛,此时任务B因为无法被执行,而暂时被挂起,只能等待执行。4. 只有执行完任务A后,才会执行任务B。
上述流程可类比: 你在吃饭,突然你老板 给你打电话,你一定要坚持吃完饭,才接你老板的电话。
(脑补一下老板的表情????)
很明显,这样处理问题,效率奇低无比。
按照我们在前情总结部分的诉求,将上述图变成这样是不是更合理些。
描述:1. 任务A进入执行区域。2. 在执行任务A的过程中,更高优先级任务B,请求被执行。3. 考虑到任务B优先级更高,则将任务A没有执行完成的部分,Stash暂存。4. 任务B被执行。当任务B被执行完成后,去执行剩余没有完成的任务A。
上述流程可类比: 你在吃饭,突然你老板给你打电话,即使你没有吃完饭,也接起了你老板的电话,后继续吃饭。(脑补一下老板的表情????)
5.核心关注
5.1 并发、调度
Concurrency & Scheduler
Concurrency 并发: 有能力优先处理更高优事务,同时对正在执行的中途任务可暂存,待高优完成后,再去执行。
concurrency is the ability of different parts or units of a program[13], algorithm[14], or problem[15] to be [executed](https://en.wikipedia.org/wiki/Execution_(computing "executed")) out-of-order or at the same time simultaneously partial order[16], without affecting the final outcome.
https://en.wikipedia.org/wiki/Concurrency_(computer_science)
Scheduler 协调调度: 暂存未执行任务,等待时机成熟后,再去安排执行剩下未完成任务。
考虑 所有任务可以被并发执行,就需要有个协调任务的调度算法。
看到这里,不知道你有没有发现一个大bug。
肯定是Call Stack[17]。
5.2 调用栈、虚拟调用栈帧
调用栈这里看起来就很不合理。
因为浏览器是利用调用栈来管理函数执行顺序的,秉承着先进后出原则,是如何做到某任务都入栈了,但是因为中途有其他事儿,就被中断。中断就不算了,还能中断后,接着后续再执行。
问题突然间就变成: pause a functioin call (暂停对一个函数的调用)。
巧了,像 generator 和 浏览器debugger 就可以做到中断函数调用。但考虑到可中断渲染,并可重回构造。React自行实现了一套体系叫做 React fiber 架构。
React Fiber 核心: 自行实现 虚拟栈帧。
That's the purpose of React Fiber. Fiber is reimplementation of the stack, specialized for React components. You can think of a single fiber as a virtual stack frame.
https://github.com/acdlite/react-fiber-architecture
看到这里,是不是觉得 React yyds。ps: 反正看不太懂的都是 yyds。
5.3 React 16 (+) 架构
6.数据结构
FiberNode.js[18]
Fiber的数据结构有三层信息: 实例属性、构建属性、工作属性。
下面以该demo代码为例:
<div id="linjiayu">123</div><script type="text/babel">const App = () => {const [sum, onSetSum] = React.useState(0)return (<div id="app 1"><h1 id="2-1 h1">标题 h1</h1><ul id="2-2 ul"> <li id="3-1 li" onClick={() => onSetSum(d => d + 1)}>点击 h2</li><li id="3-2 li">{sum}</li></ul><h3 id="2-3 h3">标题 h3</h3></div>)}ReactDOM.render(<App />,document.getElementById('linjiayu'));</script>
6.1 实例属性
该Fiber的基本信息,例如组件类型等。
6.2 构建属性
构建属性 (return、child、sibling),根据上面代码,我们构建一个Fiber树????。
构建流程
和 2.2 流程和代码解析 部分不同的是:
分为同步或异步更新。
且增加的异步更新 使用该字段 shouldYield 来判断是否需要中断。
// performSyncWorkOnRoot会调用该方法function workLoopSync() {while (workInProgress !== null) {performUnitOfWork(workInProgress);}}// performConcurrentWorkOnRoot会调用该方法function workLoopConcurrent() {while (workInProgress !== null && ! shouldYield ()) {performUnitOfWork(workInProgress);}}
在一个递归循环里,递: beginWork()[19], 归 completeWork()[20]
虚线: 表达构建关系,但未完成状态。
实线: 已构建关系,并已执行某个状态。
实线 child 和 sibling 已执行beginWork()
实线 return 已执行 completeUnitOfWork()
1. 创建fiberNode FiberRootNode 2. 创建fiberNode rootFiber (即示例中 <div id="linjiayu">)进入循环工作区域, workInProgress(工作指针指向 rootFiber)3. 创建fiberNode App beginWork() -> 只有一个子节点 -> workInProgress(工作指针指向App) 4. 创建fiberNode div beginWork() -> 有多个子节点 -> workInProgress(工作指针指向div)
5. 构建孩子们节点按照5.1 -> 5.2 -> 5.3 顺序将每个节点创建。
6. workInProgress (工作指针指向h1)beginWork() -> 没有子节点 -> completeUnitOfWork() -> 有兄弟节点,继续 ...
6.3 工作属性
【数据】数据的变更会导致UI层的变更。
【协调】为了减少对DOM的直接操作,通过Reconcile进行diff查找,并将需要变更节点,打上标签,变更路径保留在effectList里。
【调度】待变更内容要有Scheduler优先级处理。
故,涉及到diff等查找操作,是需要有个高效手段来处理前后变化,即双缓存机制。
有关双缓存机制、数据更新、diff算法等,这里不做过多介绍。
7.Reconciler 和 Scheduler
上面,我们概述了fiberNode的数据结构,链表结构即可支持随时随时中断的诉求。
下面我们简述下架构中两个核心模块:
Reconciler (协调): 负责找出变化的组件。
Scheduler (调度): 负责找出高优任务。
7.1 Reconciler 运行流程浅析
【输入】 当数据初始化或变化,最后会调用
schedulerUpdateOnFiber
该方法。
不需要调度,直接去构造fiber树。
需要调度,注册调度任务。
// scheduleUpdateOnFiber(fiber, lane, eventTime) 以下为阉割版代码// 同步if (lane === SyncLane) {if ( // Check if we're inside unbatchedUpdates (没有一次事件回调中触发多次更新)(executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering (是否尚未渲染)(executionContext & (RenderContext | CommitContext)) === NoContext) {// 不调度, 直接去构造fiber树performSyncWorkOnRoot(root);}}// 否则,需要调度交给Scheduler后,再去构造fiber树ensureRootIsScheduled(root, eventTime);
【注册任务】
ensureRootIsScheduled
两类任务:
performSyncWorkOnRoot 同步构建tree。
performConcurrentWorkOnRoot 异步构建tree。
scheduleSyncCallback 或 scheduleCallback: 将上述两类任务封装到了对应的任务队列中。
// ensureRootIsScheduledfunction ensureRootIsScheduled(root, currentTime) {// ....// 1. 优先级最高,立刻马上要同步执行if (newCallbackPriority === SyncLanePriority) {newCallbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));// 2. 同步批量更新} else if (newCallbackPriority === SyncBatchedLanePriority) {newCallbackNode = scheduleCallback(ImmediatePriority$1, performSyncWorkOnRoot.bind(null, root));} else {// 3. 异步优先级登记var schedulerPriorityLevel = lanePriorityToSchedulerPriority(newCallbackPriority);newCallbackNode = scheduleCallback(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root));}// ...// 更新rootFiber 任务root.callbackNode = newCallbackNode;}
同步任务会放到syncQueue 队列,会被立即被执行。
var _queue = syncQueue;// 执行所有同步任务runWithPriority(ImmediatePriority, () => {for (; i < queue.length; i++) {let callback = queue[i];do {callback = callback(isSync);} while (callback !== null);}});// 清空同步任务syncQueue = null;
异步处理会调用 scheduler方法 unstable_scheduleCallback
,其实是requestIdleCallback替代品,该方法传入回调任务,和过期时间,来安排任务的执行。
function unstable_scheduleCallback(callback, deprecated_options) {}
【执行任务回调】
下面 performSyncWorkOnRoot
和 performConcurrentWorkOnRoot
不同的是: 异步执行任务,可随时中断渲染 shouldYield()
同步执行构建树
function performSyncWorkOnRoot(root) {// 1. 构建树/*renderRootSync 会 调用该方法 workLoopSyncwhile (workInProgress !== null) {performUnitOfWork(workInProgress);}*/renderRootSync(root, lanes)// 2. 输出树 (可看下双缓存机制)finishedWork = root.current.alternate;}
异步执行构建树
function performConcurrentWorkOnRoot(root) {// 1. 构建树/*renderRootConcurrent 会 调用该方法 workLoopConcurrentwhile (workInProgress !== null && !shouldYield() ) {performUnitOfWork(workInProgress);}*/renderRootConcurrent(root, lanes);// 2. 输出树 (可看下双缓存机制)finishConcurrentRender(root, exitStatus, lanes);// 3. check 是否还有其他更新, 是否需要发起新调度ensureRootIsScheduled(root, now());if (root.callbackNode === originalCallbackNode) {// 当前执行的任务被中断,返回个新的,再次渲染。return performConcurrentWorkOnRoot.bind(null, root);}return null;}
【输出】
将变更内容,输出至界面。详细看 commitRoot
方法的实现。这里不做扩展。
小总结
7.2 Scheduler 运行流程浅析
workloop.js[21]
上面我们说到了同步和异步的任务,异步任务是可以中断且需要Scheduler配合处理。
注意只有异步任务即开启了并发模式,才会有时间分片。
workLoop是 实现时间切片 和 可中断渲染的核心。也是我们上面说到的虚拟栈帧的能力 。
以下为了说明,简化流程:
// 并发任务的入口function workLoopConcurrent() {// Perform work until Scheduler asks us to yield// 有任务 & 是否需要中断while (workInProgress !== null && !shouldYield() ) {performUnitOfWork(workInProgress);}}const scheduler = {// 任务放到队列里,等待空闲执行taskQueue: [{// 每个任务是个回调的概念, 且回调任务是可中断的callback: workLoopConcurrent}],// 判断: 是否需要中断, 将控制权交给主进程shouldYieldToHost () {// 没有剩余时间if (currentTime >= deadline) {// 但需要渲染 和 有更高优任务if (needsPaint || scheduling.isInputPending()) {return true; // 中断}// 是否超过 300msreturn currentTime >= maxYieldInterval;}// 还有剩余时间return false;},// 执行入口可见workLoop () {// 当前第一个任务currentTask = taskQueue[0];// 每次 currentTask 退出 就是一个时间切切片while(currentTask !== null) {// 任务没有过期, 但一帧已经无可用时间 或 需要被中断, 则让出主线程// 每一次执行均进行超时检测,做到让出主线程。if (currentTask.expirationTime > currentTime&& (!hasTimeRemaining || shouldYieldToHost())) {break}// 执行任务const callback = currentTask.callback;const continuationCallback = callback(didUserCallbackTimeout);// 如果该任务后, 还有连续回调if (typeof continuationCallback === 'function') {// 则保留当前currentTask.callback = continuationCallback;} else {// 将currentTask移除该队列pop(taskQueue);}// 更新currentTaskcurrentTask = peek(taskQueue);}},}
简而言之:
有个任务队列 queue,该队列存放可中断的任务。
workLoop
对队列里取第一个任务currentTask,进入循环开始执行。
如果任务执行完后,还有连续的回调,则 currentTask.callback = continuationCallback
否则移除已完成的任务
当该任务没有时间 或 需要中断 (渲染任务 或 其他高优任务插入等),则让出主线程。
否则执行任务 currentTask.callback()
更新任务currentTask,继续循环走起。
这里还涉及更多细节,例如:
requestAnimationFrame 计算一帧的空余时间;
使用new MessageChannel () 执行宏任务;
优先级;
...
这里不做详细说明。
8.小总结
我们想要实现并发诉求,就需要从底层重构,即FiberNode的实现。
调用栈call stack是无法做到并发 (异步可中断) 诉求,故React自行实现了一套虚拟栈帧。
虚拟栈帧 是要具备调度能力的,也就是如何在适当的时候去执行任务。
scheduler 可做到异步可中断,并可自主分配优先级高低的任务。
(即任务 (状态: 运行/中断/继续) Lane运行策略)
(实际上,scheduler + Lane 调度策略远比该处理复杂的多????)
图: 前后对比 (个人理解, 错误请指正)
以上,同学们是不是对React Fiber架构有了初步的理解哦~
其他说明
双缓存机制
参考: 双缓存Fiber树[22]
至多有两棵 Fiber Tree。
分别叫做current fiber tree 和 workInProgress fiber tree。
即在屏幕上已建立的fiber tree 和 因为数据变化重新在内存里创建的fiber tree。
他们之间是通过 alternate属性(指针) 建立连接。
简单的说:
就是workInProgress fiber的创建 是否可复用 current fiber的节点。后续可再详看diff算法。
workInProgress fiber tree 将确定要变更节点,渲染到屏幕上。
workInProgress fiber tree 晋升为 current fiber tree。
参考资料
[1]
从内部了解现代浏览器(3): https://juejin.cn/post/6844903687383416840
[2]
渲染树构建、布局及绘制: https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction
[3]
RequestIdleCallback 实验: https://github.com/Linjiayu6/FE-RequestIdleCallback-demo
[4]
RequestIdleCallback: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback
[5]
RequestIdleCallback: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback
[6]
RequestIdleCallback 实验: https://github.com/Linjiayu6/FE-RequestIdleCallback-demo
[7]
React: stack reconciler实现: https://zh-hans.reactjs.org/docs/implementation-notes.html
[8]
React 算法之深度优先遍历: https://juejin.cn/post/6912280245055782920
[9]
调用栈: https://segmentfault.com/a/1190000010360316
[10]
Leetcode: 斐波拉契数列: https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/
[11]
Leetcode: 70. 爬楼梯: https://leetcode-cn.com/problems/climbing-stairs/
[12]
ReactFiberWorkLoop.old.js: https://github.com/facebook/react/blob/v17.0.1/packages/react-reconciler/src/ReactFiberWorkLoop.old.js#L1558
[13]
program: https://en.wikipedia.org/wiki/Computer_program
[14]
algorithm: https://en.wikipedia.org/wiki/Algorithm
[15]
problem: https://en.wikipedia.org/wiki/Problem_solving
[16]
partial order: https://en.wikipedia.org/wiki/Partial_Order
[17]
Call Stack: https://segmentfault.com/a/1190000021456103
[18]
FiberNode.js: https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/react-reconciler/src/ReactFiber.new.js#L117
[19]
beginWork(): https://github.com/facebook/react/blob/970fa122d8188bafa600e9b5214833487fbf1092/packages/react-reconciler/src/ReactFiberBeginWork.new.js#L3058
[20]
completeWork(): https://github.com/facebook/react/blob/970fa122d8188bafa600e9b5214833487fbf1092/packages/react-reconciler/src/ReactFiberCompleteWork.new.js#L652
[21]
workloop.js: https://github.com/facebook/react/blob/v17.0.1/packages/scheduler/src/Scheduler.js#L164
[22]
双缓存Fiber树: https://react.iamkasong.com/process/doubleBuffer.html#update%E6%97%B6
【React】1077- React Fiber架构浅析相关推荐
- 理解React框架的Fiber架构
React为什么要使用Fiber 架构 以下内容引用修言的<深入浅出搞定react>课程,该文通俗易懂,由浅入深,一步步剖析react原理,有兴趣的朋友可以去拉钩教育前端模块找他的课程,附 ...
- 前端React教程第六课 认识栈调和、setState和Fiber架构
10 React 中的"栈调和"(Stack Reconciler)过程是怎样的? 时下 React 16 乃至 React 17 都是业界公认的"当红炸子鸡" ...
- react 日期怎么格式化_手写React的Fiber架构,深入理解其原理
熟悉React的朋友都知道,React支持jsx语法,我们可以直接将HTML代码写到JS中间,然后渲染到页面上,我们写的HTML如果有更新的话,React还有虚拟DOM的对比,只更新变化的部分,而不重 ...
- 转载:React Fiber架构(浅显易懂)
性能优化是一个系统性的工程,如果只看到局部,引入算法,当然是越快越好; 但从整体来看,在关键点引入缓存,可以秒杀N多算法,或另辟蹊径,探索事件的本质,可能用户要的并不是快-- React16启用了全新 ...
- React系列——React Fiber 架构介绍资料汇总(翻译+中文资料)
原文 react-fiber-architecture 介绍 React Fibre是React核心算法正在进行的重新实现.它是React团队两年多的研究成果. React Fiber的目标是提高其对 ...
- 手写简易版 React 来彻底搞懂 fiber 架构
React 16 之前和之后最大的区别就是 16 引入了 fiber,又基于 fiber 实现了 hooks.整天都提 fiber,那 fiber 到底是啥?它和 vdom 是什么关系? 与其看各种解 ...
- react源码中的fiber架构
先看一下FiberNode在源码中的样子 FiberNode // packages/react-reconciler/src/ReactFiber.old.js function FiberNode ...
- react fiber架构学习
同步更新过程的局限 在v16版本以前,react的更新过程是通过递归从根组件树开始同步进行的,更新过程无法被打断,当组件树很大的时候就会出现卡顿的问题 react中的虚拟dom import Reac ...
- React Fiber架构原理剖析
一.概述 在 React 16 之前,VirtualDOM 的更新采用的是Stack架构实现的,也就是循环递归方式.不过,这种对比方式有明显的缺陷,就是一旦任务开始进行就无法中断,如果遇到应用中组件数 ...
最新文章
- php 5.2.17 mysql_Apache 2.2.15 整合php 5.2.17 Mysql-5.5.8
- Android App截包工具
- Android-PullLayout
- python rsa_python rsa加解密
- CentOS6.3的Grub启动项的menu.lst文件内容
- 暴力/图论 hihoCoder 1179 永恒游戏
- 高中职业学校计算机专业题,职业高中高考计算机专业试题3.doc
- kafka生产数据时的应答机制(ACK)
- 主流数据库连接池性能比较 hikari druid c3p0 dbcp jdbc
- 从零開始学androidlt;TabHost标签组件.二十九.gt;
- iptables的基础知识-iptables中的ICMP
- 什么是ANC降噪技术?耳机工厂来告诉你
- 自考科目列表,自考本科,题库,自学考试,历年真题
- Linux中断机制(二)
- 如何实现Excel多人共享与协作
- CSS实现图片自适应布局
- HTTPResponse
- 贪吃蛇-EasyX版
- 数据分析|数据分析如何做呢?
- Unity 面试题汇总(三)Unity 基础相关
热门文章
- 解决freemarker生成的静态文件中文乱码的问题
- jQuery实现动态瀑布流布局效果
- SQL中先排序再筛选与先筛选再排序
- 买飞机票牵涉到的业务逻辑,
- 全职高手服务器不稳定,【答疑/科普向】全职高手常见“漏洞”
- 2013年计算机网络原理,全国2013年4月自学考试计算机网络原理试题
- 连接kafka报错:1 partitions have leader brokers without a matching listener
- 互联网业务实战(二)--大数据在头条的应用(离线和实时数据处理)
- Docker 容器下载 及 基本操作指令
- 如果他们在未来的几年内技术水平没有突破性的提升,或者缺乏一点灵性和品味,那么可能在未来很长一段时间内,他们都会保持这个薪资水平(转)...