You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/** @noinline */
function workLoopConcurrent() {
// Perform work until Scheduler asks us to yield
while (workInProgress !== null && !shouldYield()) {
workInProgress = performUnitOfWork(workInProgress);
}
}
react的理念是构建快速响应的web应用程序,为了达成快速响应,首先就要避免页面的卡顿和掉帧。
而导致页面卡顿和掉帧的原因主要有一个:
时间切片-可中断的异步更新
现在主流浏览器刷新频率是60Hz,也就是每(1000ms/60Hz)16.6ms刷新一次。
由于JS线程和GUI渲染线程是互斥的,所以JS执行与页面布局、页面渲染不能同时执行。
当JS遇到大计算量的操作,执行时间超过了16.6ms时,这次刷新就没有剩余时间留给页面布局和渲染了,就会引起卡顿和掉帧。
React是如何解决这个问题的呢?其实道理也很简单,就是将需要大量时间执行的长任务切分成一段一段的短任务,化繁为简。
在浏览器每一帧的时间里,React预留一部分时间给自己更新组件,当预留时间不够用时,就把线程控制权交还给GUI线程使其有时间来渲染UI,React则等到下一帧时间来继续被中断的任务。
总结来说,解决JS大计算量操作或设备性能不足导致的卡顿,关键就是将同步的更新变为可中断的异步更新。
React15架构
React15架构可以分为两部分:
Reconciler(协调器)
在React中可以通过
this.setState
、this.forceUpdate
、ReactDOM.render
等API来触发更新。每当有更新发生时,Reconciler都会做以下工作:
Renderer(渲染器)
在每次更新,Render接收到Reconciler的通知时,就会把变化的虚拟DOM渲染到当前宿主环境。
React15架构的缺点
在Reconciler中,
mount
的组件会调用mountComponent
方法,update
的组件会调用updateComponent
方法。这两个方法都会将JSX递归创建为虚拟DOM,更新组件及其所有子组件。
由于采用了递归更新,所以当递归的层级过深(嵌套的组件过多),更新时间超过了16.6ms时,用户就会感知到卡顿。
在上面已经提出了解决的方法,就是采用时间切片来分割长任务,将同步更新变为可中断的异步更新。
但可惜的是React15并不支持这样做,因为在React15中Reconciler和Renderer是交替工作的,是同步不可中断的。
如果中断就会导致DOM更新不完全的问题,所以在React16中,整个架构都重写了。
React16架构
React16架构可以分为三部分:
Scheduler(调度器)
Scheduler负责在浏览器有剩余时间进行通知,让Reconciler继续工作。并且还能调度任务的优先级,高优先级的任务先进入Reconciler。
Reconciler(协调器)
在React15中,Reconciler是以递归的方式来处理虚拟DOM的,这种方式存在不可中断的弊端。
在React16中,Reconciler内部采用了Fiber的架构,递归变成了可中断的循环过程,每次循环都会调用
shouldYield
来判断是否有剩余时间。并且在React16中,Reconciler和Renderer不再是交替工作。而是在Scheduler将任务交给Reconciler后,Reconciler会给所有变化的虚拟DOM打上标记,最后统一交给Renderer处理。
需要注意的是,整个Scheduler与Reconciler的工作都在内存中进行,只有两个原因会中断工作:
Renderer(渲染器)
Renderer根据Reconciler为虚拟DOM打的标记,同步执行对应的DOM操作。
由于整个Scheduler与Reconciler的工作都在内存中进行,即使任务反复中断,用户也不会看到更新不完全的DOM。
参考
React技术揭秘
The text was updated successfully, but these errors were encountered: