Fiber는 React의 새로운 스케줄링 알고리즘이자 핵심 알고리즘을 재구현한 것입니다. React Fiber는 업데이트 프로세스를 조각화합니다. 각 업데이트 프로세스가 실행된 후 긴급한 작업이 있는지 확인하기 위해 React의 작업 조정 모듈로 제어가 반환됩니다.
이 튜토리얼의 운영 환경: Windows 7 시스템, 반응 버전 17.0.1, Dell G3 컴퓨터.
Fiber는 React16 버전 이후에 도입되었습니다. 전체 아키텍처 수준의 스케줄링, 조정, 비교 알고리즘 및 렌더링은 Fiber와 밀접한 관련이 있습니다.
react가 구성 요소를 렌더링할 때 setState 시작부터 렌더링 완료까지 전체 프로세스가 동기식입니다("all in one go"). 렌더링해야 하는 구성 요소가 상대적으로 큰 경우 js 실행은 메인 스레드를 오랫동안 점유하게 되어 페이지의 응답성이 저하되고 애니메이션 및 제스처와 같은 애플리케이션에서 반응의 효율성이 떨어집니다.
이 문제를 해결하기 위해 React 팀은 2년 간의 작업 끝에 React-Reconciliation의 핵심 알고리즘을 다시 작성했습니다. 그리고 이 새로운 기능이 v16 버전에 출시되었습니다. 이전 reconciler와 후속 reconciler를 구별하기 위해 이전 reconciler를 보통 stack reconciler라고 부르고, 다시 작성된 reconciler를 Fiber reconciler, 줄여서 Fiber라고 부릅니다.
공식 설명은 "React Fiber는 핵심 알고리즘을 재구현한 것입니다."입니다.
Fiber는 복잡한 React 애플리케이션의 응답성과 성능을 향상시킬 수 있습니다. Fiber는 React의 새로운 스케줄링 알고리즘(조정 알고리즘)
React Fiber는 업데이트 프로세스가 실행된 후 작업 조정을 담당하는 React 모듈로 제어권이 반환되어 다른 긴급 작업이 있는지 확인합니다. 아니요, 계속 업데이트하세요. 긴급한 작업이 있으면 긴급한 작업을 수행하세요.
react가 구성 요소를 렌더링할 때 setState 시작부터 렌더링 완료까지 전체 프로세스가 동기식입니다("all in one go"). 렌더링해야 하는 구성 요소가 상대적으로 큰 경우 js 실행은 메인 스레드를 오랫동안 점유하게 되어 페이지의 응답성이 저하되고 애니메이션 및 제스처와 같은 애플리케이션에서 반응의 효율성이 떨어집니다.
이 문제를 해결하기 위해 React 팀은 2년 간의 작업 끝에 React의 핵심 알고리즘인 reconciliation을 다시 작성했습니다. 그리고 이 새로운 기능이 v16 버전에 출시되었습니다. 이전 reconciler와 후속 reconciler를 구별하기 위해 이전 reconciler를 일반적으로 stack reconciler라고 하고, 다시 작성된 reconciler를 Fiber reconciler, 줄여서 Fiber라고 합니다.
스택 조정자의 작업 흐름은 함수 호출 프로세스와 매우 유사합니다. 상위 구성 요소의 하위 구성 요소를 조정하는 것은 함수의 재귀와 비교할 수 있습니다(이것이 스택 조정자라고 불리는 이유입니다). setState 이후, React는 상위 노드(Virtual DOM)에서 시작하여 차이점을 찾기 위해 순회하는 조정 프로세스를 즉시 시작합니다. 모든 가상 DOM 순회가 완료된 후 조정자는 수정해야 하는 현재 정보를 실제 DOM에 제공하고 이를 렌더링을 위해 렌더러에 전달한 다음 업데이트된 콘텐츠가 화면에 표시됩니다. 특히 큰 vDOM 트리의 경우 조정 프로세스가 매우 길어집니다(x00ms). 이 기간 동안 기본 스레드는 js에 의해 점유되므로 모든 상호 작용, 레이아웃 및 렌더링이 중지되어 사용자에게 페이지가 다음과 같은 느낌을 줍니다. 갇힌. .
스케줄링은 주로 언제 수행해야 하는지를 결정하는 Fiber 조정 프로세스입니다. ? 프로세스는 스택 조정자에서 조정이 "한 번에" 이루어짐을 보여줍니다. 함수의 경우 함수의 실행 결과만 원하기 때문에 문제가 되지 않지만 UI의 경우 다음 문제도 고려해야 합니다.
따라서 이상적으로는 조정 프로세스가 아래 그림과 같아야 합니다. 한 번에 작은 작업만 수행한 후 "숨을 쉬고" 돌아갈 수 있습니다. 우선순위가 높은 작업을 먼저 처리해야 합니다. 그렇지 않은 경우 실행이 계속됩니다(협동 스케줄링).
먼저 스택 조정기에서 반응이 어떻게 작동하는지 살펴보겠습니다. 코드에서 일부 요소를 생성(또는 업데이트)하고, React는 이러한 요소를 기반으로 Virtual DOM을 생성(또는 업데이트)한 다음, React는 업데이트 전후의 가상 DOM 간의 차이를 기반으로 실제 DOM을 수정합니다. 스택 조정자에서 DOM 업데이트는 동기식입니다. 즉, 가상 DOM의 비교 프로세스 중에 인스턴스가 업데이트된 것으로 확인되면 DOM 작업이 즉시 수행됩니다 .
Fiber-conciler에서는 작업이 여러 개의 작은 부분으로 나누어져 중단될 수 있으므로 DOM을 동기적으로 작동하면 Fiber-tree가 실제 DOM과 동기화되지 않을 수 있습니다. 각 노드마다 해당 요소의 기본 정보를 저장할 뿐만 아니라 작업 스케줄링을 위한 일부 정보도 저장합니다. 따라서 Fiber는 조정 단계에서 분할될 수 있는 가장 작은 작업 단위를 나타내는 객체일 뿐이며, 위 그림의 반응 인스턴스와 일대일로 대응합니다. stateNode
속성을 통해 인스턴스 자체의 특성을 관리합니다. 현재 작업 단위의 다음 작업 단위는 자식과 형제로 표현되며, return은 처리가 완료된 후 반환된 결과와 병합될 대상을 나타내며 일반적으로 부모 노드를 가리킵니다. 전체 구조는 연결된 목록 트리입니다. 각 작업 단위(파이버)의 실행이 완료된 후 여전히 메인 스레드 타임 슬라이스가 있는지 확인합니다. 그렇지 않은 경우 우선 순위가 높은 다른 트랜잭션이 먼저 처리되고 실행됩니다. 메인 스레드가 자유로워질 때까지 계속됩니다. stateNode
属性管理Instance自身的特性。通过child和sibling表征当前工作单元的下一个工作单元,return表示处理完成后返回结果所要合并的目标,通常指向父节点。整个结构是一个链表树。每个工作单元(fiber)执行完成后,都会查看是否还继续拥有主线程时间片,如果有继续下一个,如果没有则先处理其他高优先级事务,等主线程空闲下来继续执行。
fiber { stateNode: {}, child: {}, return: {}, sibling: {}, }复制代码
当前页面包含一个列表,通过该列表渲染出一个button和一组Item,Item中包含一个div,其中的内容为数字。通过点击button,可以使列表中的所有数字进行平方。另外有一个按钮,点击可以调节字体大小。
页面渲染完成后,就会初始化生成一个fiber-tree。初始化fiber-tree和初始化Virtual DOM tree没什么区别,这里就不再赘述。
于此同时,react还会维护一个workInProgressTree。workInProgressTree用于计算更新,完成reconciliation过程。
用户点击平方按钮后,利用各个元素平方后的list调用setState,react会把当前的更新送入list组件对应的update queue中。但是react并不会立即执行对比并修改DOM的操作。而是交给scheduler去处理。
scheduler会根据当前主线程的使用情况去处理这次update。为了实现这种特性,使用了requestIdelCallback
API。对于不支持这个API的浏览器,react会加上pollyfill。
总的来讲,通常,客户端线程执行任务时会以帧的形式划分,大部分设备控制在30-60帧是不会影响用户体验;在两个执行帧之间,主线程通常会有一小段空闲时间,requestIdleCallback
setState({}, callback); // stack concilersetState(() => { return {} }, callback); // fiber conciler复制代码
예를 들어현재 페이지에는 버튼과 항목 세트가 렌더링되는 목록이 포함되어 있습니다. 항목에는 내용이 숫자인 div가 포함되어 있습니다. 버튼을 클릭하면 목록의 모든 숫자를 제곱할 수 있습니다. 글꼴 크기를 조정하기 위해 클릭할 수 있는 버튼도 있습니다.
page 렌더링이 완료되면 Fiber-Tree가 초기화되어 생성됩니다. 파이버 트리 초기화와 가상 DOM 트리 초기화 사이에는 차이가 없으므로 여기서는 자세히 설명하지 않겠습니다.
🎜🎜🎜 유 동시에 React는 workInProgressTree도 유지합니다. workInProgressTree는 업데이트를 계산하고 조정 프로세스를 완료하는 데 사용됩니다. 🎜🎜🎜🎜사용자 사각형 버튼을 클릭한 후 각 요소의 제곱 목록을 사용하여 setState를 호출하면 반응은 현재 업데이트를 목록 구성 요소에 해당하는 업데이트 대기열로 보냅니다. 그러나 React는 즉시 비교를 수행하고 DOM 작업을 수정하지 않습니다. 대신 스케줄러에게 맡기세요. 🎜🎜🎜🎜스케줄러 이 업데이트는 기본 스레드의 현재 사용량에 따라 처리됩니다. 이 기능을 구현하려면requestIdelCallback
API가 사용됩니다. 이 API를 지원하지 않는 브라우저의 경우 React는 pollyfill을 추가합니다. 🎜🎜일반적으로 클라이언트 스레드는 작업을 실행할 때 프레임으로 구분됩니다. 대부분의 장치는 두 실행 프레임 사이에서 사용자 경험에 영향을 주지 않고 30~60프레임을 제어합니다. code>requestIdleCallback은 🎜Idle Period🎜 동안 🎜Idle Callback🎜을 호출하여 일부 작업🎜🎜🎜🎜을 수행할 수 있습니다.低优先级任务由requestIdleCallback
处理;
高优先级任务,如动画相关的由requestAnimationFrame
处理;
requestIdleCallback
可以在多个空闲期调用空闲期回调,执行任务;
requestIdleCallback
方法提供deadline,即任务执行限制时间,以切分任务,避免长时间执行,阻塞UI渲染而导致掉帧;
一旦reconciliation过程得到时间片,就开始进入work loop。work loop机制可以让react在计算状态和等待状态之间进行切换。为了达到这个目的,对于每个loop而言,需要追踪两个东西:下一个工作单元(下一个待处理的fiber);当前还能占用主线程的时间。第一个loop,下一个待处理单元为根节点。
因为根节点上的更新队列为空,所以直接从fiber-tree上将根节点复制到workInProgressTree中去。根节点中包含指向子节点(List)的指针。
根节点没有什么更新操作,根据其child指针,接下来把List节点及其对应的update queue也复制到workinprogress中。List插入后,向其父节点返回,标志根节点的处理完成。
根节点处理完成后,react此时检查时间片是否用完。如果没有用完,根据其保存的下个工作单元的信息开始处理下一个节点List。
接下来进入处理List的work loop,List中包含更新,因此此时react会调用setState时传入的updater funciton获取最新的state值,此时应该是[1,4,9]。通常我们现在在调用setState传入的是一个对象,但在使用fiber conciler时,必须传入一个函数,函数的返回值是要更新的state。react从很早的版本就开始支持这种写法了,不过通常没有人用。在之后的react版本中,可能会废弃直接传入对象的写法。
setState({}, callback); // stack concilersetState(() => { return {} }, callback); // fiber conciler复制代码
在获取到最新的state值后,react会更新List的state和props值,然后调用render,然后得到一组通过更新后的list值生成的elements。react会根据生成elements的类型,来决定fiber是否可重用。对于当前情况来说,新生成的elments类型并没有变(依然是Button和Item),所以react会直接从fiber-tree中复制这些elements对应的fiber到workInProgress 中。并给List打上标签,因为这是一个需要更新的节点。
List节点处理完成,react仍然会检查当前时间片是否够用。如果够用则处理下一个,也就是button。加入这个时候,用户点击了放大字体的按钮。这个放大字体的操作,纯粹由js实现,跟react无关。但是操作并不能立即生效,因为react的时间片还未用完,因此接下来仍然要继续处理button。
button没有任何子节点,所以此时可以返回,并标志button处理完成。如果button有改变,需要打上tag,但是当前情况没有,只需要标记完成即可。
老规矩,处理完一个节点先看时间够不够用。注意这里放大字体的操作已经在等候释放主线程了。
接下来处理第一个item。通过shouldComponentUpdate钩子可以根据传入的props判断其是否需要改变。对于第一个Item而言,更改前后都是1,所以不会改变,shouldComponentUpdate返回false,复制div,处理完成,检查时间,如果还有时间进入第二个Item。
第二个Item shouldComponentUpdate返回true,所以需要打上tag,标志需要更新,复制div,调用render,讲div中的内容从2更新为4,因为div有更新,所以标记div。当前节点处理完成。
위 상황의 경우 div는 이미 리프 노드이고 형제 노드가 없으며 해당 값이 업데이트되었습니다. 이때 이 노드의 변경으로 생성된 효과를 상위 노드에 병합해야 합니다. 이때 React는 효과를 생성하는 모든 요소를 기록하는 목록을 유지합니다.
병합 후 상위노드 아이템으로 돌아가면 상위노드 마크가 완성됩니다.
다음 작업 단위는 아이템입니다. 아이템 진입 전 시간을 확인해주세요. 그러나 이번에는 시간이 다되었습니다. 이 시점에서 React는 메인 스레드를 교체하고 나중에 나머지 작업을 완료하기 위해 시간을 할당하도록 메인 스레드에 지시해야 합니다.
다음으로 메인 스레드는 글꼴을 확대하는 작업을 수행합니다. 완료 후, 이전 Item의 처리 과정과 거의 동일하게 React의 다음 작업을 실행합니다. 처리가 완료된 후 전체 Fiber-Tree와 workInProgress는 다음과 같습니다.
완료 후, 항목이 목록으로 반환되고 효과가 병합됩니다. 이제 효과 목록은 다음과 같습니다.
이 때 목록은 루트 노드로 돌아가 효과를 병합하며 모든 노드는 완료로 표시될 수 있습니다. 현재 React는 workInProgress를 보류 중인 Commit으로 표시합니다. 이는 커밋 단계에 들어갈 수 있음을 의미합니다.
이때 해야 할 일은 시간이 충분한지 확인하는 것입니다. 시간이 없다면 수정 사항을 DOM에 제출할 때까지 기다리세요. 2단계에 들어간 후 reacDOM은 1단계에서 계산된 효과 목록을 기반으로 DOM을 업데이트합니다.
DOM을 업데이트한 후 workInProgress는 DOM과 완전히 일치합니다. 현재 파이버 트리와 DOM의 일관성을 유지하기 위해 React는 현재 및 workinProgress 포인터를 교환합니다.
사실 React는 대부분 두 개의 트리(이중 버퍼링)를 유지합니다. 이렇게 하면 다음 업데이트 중에 메모리를 할당하고 가비지를 정리하는 데 필요한 시간을 줄일 수 있습니다. 커밋이 완료된 후, componentDidMount 함수를 실행합니다.
조정 프로세스를 작은 작업 단위로 나누면 페이지가 브라우저 이벤트에 보다 시기적절하게 응답할 수 있습니다. 그러나 또 다른 문제는 아직 해결되지 않았습니다. 즉, 현재 처리 중인 React 렌더링이 오랜 시간이 걸리면 후속 React 렌더링이 여전히 차단된다는 것입니다. 이것이 Fiber Reconciler가 우선순위 전략을 추가하는 이유입니다.
【관련 추천: Redis 동영상 튜토리얼】
위 내용은 반응하는 섬유는 무엇입니까의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!