ホームページ >ウェブフロントエンド >フロントエンドQ&A >反応するファイバーとは何ですか
Fiber は React の新しいスケジューリング アルゴリズムであり、コア アルゴリズムを再実装したものです。 React Fiber は更新プロセスを断片化します。各更新プロセスが実行された後、制御は React のタスク調整モジュールに返され、他に実行すべき緊急タスクがあるかどうかが確認されます。緊急タスクがある場合は、緊急タスクだけを実行します。
このチュートリアルの動作環境: Windows7 システム、react17.0.1 バージョン、Dell G3 コンピューター。
ファイバーは、react16 バージョンの後に導入され、アーキテクチャーレベル全体でのスケジューリング、調整、差分アルゴリズム、レンダリングはファイバーと密接に関連しています。
react がコンポーネントをレンダリングする場合、setState の開始からレンダリングの完了までのプロセス全体が同期 (「オールインワン」) されます。レンダリングする必要があるコンポーネントが比較的大きい場合、js の実行が長時間メイン スレッドを占有することになり、ページの応答性が低下し、アニメーションやジェスチャなどのアプリケーションでの反応が低下します。
この問題を解決するために、react チームは 2 年間の作業を経て、react-reconciliation のコア アルゴリズムを書き直しました。そして、この新機能は v16 バージョンでリリースされました。前後のリコンサイラを区別するために、通常、以前のリコンサイラをスタック・リコンサイラと呼び、書き換えられたリコンサイラをファイバー・リコンサイラー、または略してファイバーと呼びます。
公式の説明は「React Fiber はコア アルゴリズムを再実装したものです。」です。
Fiber は、複雑な React アプリケーションの応答性とパフォーマンスを向上させることができます。 Fiber は React の新しいスケジューリング アルゴリズム (調整アルゴリズム)
React Fiber は更新プロセスを断片化します。各更新プロセスが実行された後、制御が React のモジュールに返され、タスクの調整を担当して、緊急のタスクがあるかどうかを確認します。緊急のタスクがない場合は更新を続行し、緊急のタスクがある場合は緊急のタスクを実行します。
react がコンポーネントをレンダリングする場合、setState の開始からレンダリングの完了までのプロセス全体が同期 (「オール イン ワン ゴー」) されます。レンダリングする必要があるコンポーネントが比較的大きい場合、js の実行が長時間メイン スレッドを占有することになり、ページの応答性が低下し、アニメーションやジェスチャなどのアプリケーションでの反応が低下します。
この問題を解決するために、react チームは 2 年間の作業 - 調整を経て、react のコア アルゴリズムを書き直しました。そして、この新機能は v16 バージョンでリリースされました。前後のリコンサイラを区別するために、通常、以前のリコンサイラをスタック・リコンサイラと呼び、書き換えられたリコンサイラをファイバー・リコンサイラー、または略してファイバーと呼びます。
スタックリコンサイラーのワークフローは、関数呼び出しプロセスと非常によく似ています。親コンポーネント内のサブコンポーネントの調整は、関数の再帰に例えることができます (これがスタック リコンサイラーと呼ばれる理由です)。 setState の後、react はすぐに調整プロセスを開始し、親ノード (仮想 DOM) から開始してトラバースして違いを見つけます。すべての仮想 DOM トラバーサルが完了すると、リコンサイラーは、変更が必要な現在の情報を実際の DOM に提供し、それをレンダリングのためにレンダラに渡すことができます。その後、更新されたコンテンツが画面に表示されます。特に大きな vDOM ツリーの場合、調整プロセスは非常に長くなります (x00ms)。この期間中、メイン スレッドは js によって占有されるため、インタラクション、レイアウト、レンダリングが停止し、ユーザーはページが開いているように感じます。立ち往生。 。
スケジューリングはファイバー調整のプロセスであり、主にいつ何を行うべきかを決定します。 ? のプロセスは、スタック リコンサイラーではリコンシリエーションが「すべて一度に」行われることを示しています。関数の場合、関数の実行結果のみが必要なので、これは問題ありませんが、UI の場合は、次の問題も考慮する必要があります。 :
への応答を優先する必要があります。したがって、理想的には、調整プロセスは次の図のようになり、小さなタスクが 1 つだけ含まれるようになります。終了後、「一呼吸」してメインスレッドに戻り、処理する必要のある優先度の高いタスクがあるかどうかを確認します。ある場合は、優先度の高いタスクを最初に処理します。ない場合は、実行を継続します (協調スケジューリング) タイプのスケジューリング)。
まず、スタックリコンサイラーの下で React がどのように動作するかを見てみましょう。コード内にいくつかの要素を作成 (または更新) し、react はこれらの要素に基づいて仮想 DOM を作成 (または更新) し、更新前と更新後の仮想 DOM の違いに基づいて実際の DOM を変更します。 スタック リコンサイラでは、DOM 更新は同期的であることに注意してください。つまり、仮想 DOM の比較プロセス中に、インスタンスが更新されたことが判明すると、DOM 操作 が直ちに実行されます。
fiber-conciler では、操作が多くの小さな部分に分割され、中断される可能性があるため、DOM の同期操作によりファイバー ツリーと実際の操作の間に不整合が生じる可能性があります。 DOM を同期します。各ノードについて、対応する要素の基本情報を保存するだけでなく、タスクのスケジューリングのための情報も保存します。したがって、ファイバーは単なるオブジェクトであり、調整フェーズ中に分割できる作業の最小単位を表し、上の図の反応インスタンスに 1 対 1 で対応します。 stateNode
属性を通じてインスタンス自体の特性を管理します。現在のワークユニットの次のワークユニットは子と兄弟で表され、return は処理完了後に返された結果とマージされるターゲットを示し、通常は親ノードを指します。全体の構造はリンク リスト ツリーです。各ワークユニット (ファイバー) の実行が完了した後、メインスレッドのタイムスライスがまだあるかどうかをチェックします。残っている場合は次のトランザクションに進みます。そうでない場合は、他の優先度の高いトランザクションが最初に処理され、実行が完了します。メインスレッドが空くまで続行されます。
fiber { stateNode: {}, child: {}, return: {}, sibling: {}, }复制代码
現在のページには、ボタンとアイテムのセットがレンダリングされるリストが含まれています。アイテムには div が含まれています。内容は数値です。ボタンをクリックすると、リスト内のすべての数値を 2 乗することができます。クリックしてフォント サイズを調整できるボタンもあります。
#ページのレンダリングが完了すると、ファイバー ツリーが初期化されて生成されます。ファイバーツリーの初期化と仮想 DOM ツリーの初期化には違いがないため、ここでは詳しく説明しません。
同時に、react は workInProgressTree も維持します。 workInProgressTree は、更新を計算し、調整プロセスを完了するために使用されます。
#ユーザーが四角形のボタンをクリックすると、各要素の四角形のリストを使用して setState が呼び出され、React はリスト コンポーネントに対応する更新キューに現在の更新を送信します。 。ただし、react はすぐに比較を実行して DOM 操作を変更するわけではありません。代わりに、スケジューラに任せてください。
#スケジューラは、メインスレッドの現在の使用状況に基づいてこの更新を処理します。この機能を実装するには、requestIdelCallback
API を使用します。この API をサポートしていないブラウザの場合、react はpollyfill を追加します。
一般的に言えば、通常、クライアント スレッドはタスクを実行するときにフレームに分割されます。ほとんどのデバイスは、ユーザー エクスペリエンスに影響を与えることなく 30 ~ 60 フレームを制御します。2 つの実行フレームの間に、メイン スレッドには通常、短期間のアイドル時間があります。 requestIdleCallback
は、この アイドル期間 (アイドル期間) 中に 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 はメインスレッドをスワップし、残りの操作を完了するために今後メインスレッドに時間を割り当てるように指示する必要があります。
メインスレッドは次にフォントを拡大する操作を実行します。完了後、次のreact操作を実行しますが、これは前項目の処理とほぼ同様で、処理完了後のファイバーツリー全体とworkInProgressは以下のようになります。
完了後、アイテム リストが戻り、エフェクトがマージされます。エフェクト リストは次のようになります:
この時点で、リストはルート ノードを作成してエフェクトをマージすると、すべてのノードを完了としてマークできます。現時点では、react は workInProgress を pendingCommit としてマークします。これは、コミット段階に入ることができることを意味します。
この時点で、時間が十分かどうかを確認する必要があります。時間がない場合は、修正を送信する時間まで待ちます。 DOM。ステージ 2 に入ると、reacDOM はステージ 1 で計算されたエフェクトリストに基づいて DOM を更新します。
DOM を更新した後、workInProgress は DOM と完全に一致します。現在のファイバーツリーと DOM の一貫性を保つために、react は current ポインターと workinProgress ポインターを交換します。
実際、react はほとんどの場合 2 つのツリー (ダブルバッファリング) を維持します。これにより、次回の更新時にメモリを割り当てたり、ガベージをクリーンアップしたりする時間を短縮できます。コミットが完了したら、componentDidMount 関数を実行します。
概要
調整プロセスを小さな作業単位に分解することで、ページはよりタイムリーにブラウザ イベントに応答できます。しかし、別の問題はまだ解決されていません。つまり、現在処理中の反応レンダリングに長時間かかる場合、後続の反応レンダリングは依然としてブロックされてしまいます。そのため、ファイバー リコンサイラーは優先戦略を追加します。 [関連する推奨事項:以上が反応するファイバーとは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。