ブラウザ
 Computer >> コンピューター >  >> ソフトウェア >> ブラウザ

React キャッシュ、タイム スライシング、同期 API フェッチの詳細

React キャッシュ、タイム スライシング、同期 API フェッチの詳細

マービン・フラシェット

さて、今年はReactの年になりそうです。おそらく、16.7-alpha.0 に搭載される新しいキラー機能であるフックについて聞いたことがあるでしょう。おそらく、タイム スライシングやサスペンスなど、その他の素晴らしくてクールなものについても聞いたことがあるでしょう。

この記事はそうではありません いくつかの新機能の使用方法を説明することを目的とするのではなく、それらがどのように構築されたかを証明することを目的としています。私たちが何をしようとしているのかを理解するためです。

私がその機能を発見した方法でも書かれています。おそらく考えられた方法ではないかもしれませんが、これが私がポイントを獲得した方法です。

読んでいるとわかること:

  • 非同期 JavaScript とイベント ループ
  • React の代数効果と例
  • ファイバーフェーズとリアクトフェーズ

この投稿を書いた理由

この記事を書こうと思ったきっかけは、 この非同期の使用を可能にする特別かつ実験的な機能でした。 同期を使用した操作 API:

const bulbasaur = ApiResource.read() ?…何? 同期 ?!

React-cache ライブラリは、同期 API で非同期操作を使用する機能を作成します。これは、React が内部でどのように動作するかを知りたいと思ったきっかけとなった機能です。以下は、このライブラリに関する Dan Abramov と Andrew Clark によるプレゼンテーションです。

どうしてそんなことが可能なのでしょうか?同期呼び出しを使用してリモート データを取得するにはどうすればよいですか?

この例を深く掘り下げて、react-cache がそのような機能をどのように実装するかを理解し、それがどのように機能するかを確認してみましょう。この物語はファイバー アーキテクチャから始まります。

JavaScript 操作の制御

ファイバー アーキテクチャにより、React がタスクの実行を制御できるようになります。 React が抱えていた複数の問題を解決するために構築されました。私の注意を引いた 2 つは次のとおりです。

  • データの取得よりもユーザー入力など、特定のイベントを優先する
  • React の計算を非同期に分割してメインスレッドの可用性を維持し、長時間のレンダリング プロセス中にメインスレッドがブロックされるのを回避する

React に限らず、JavaScript アプリケーション内で状態変化を引き起こすものはすべて、非同期操作が原因です。これらには setTimeout が含まれます 、fetch 、イベントのリスナー。

非同期操作は、複数の JavaScript コア概念を通じて管理されます。

  • タスク (マイクロ、マクロ、レンダリングなど)
  • イベントループ
  • コールスタック

これらの概念に詳しくない場合は、Jake Archibald によるこのビデオをご覧になることをお勧めします。

ファイバーのおかげで、 ユーザー入力は解決されます。 フェッチ呼び出しなどの他の非同期操作の前。

どうしてそんなことが可能なのでしょうか?

さて、Archibald の上記の話は、イベント ループがどのように機能するかを学ぶ私自身の道の最初の敷石でした。たとえば、Promise API を通じて生成されたマイクロタスクは事前に実行され、フラッシュされると彼は言います。 次のマクロタスク。このプロセスでは、setTimeout などのコールバックベースのメソッドが使用されます。 .

さて、私の「ユーザー入力とデータの取得」の比較を覚えていると思いますが、チームはどのようにして fetch を作成したのでしょうか。 解決 onChange 解決策は?

これらの概念はいずれも、同じ仕様である WhatWG / HTML5 / Ecma-262 には適合せず、ブラウザや JS エンジンなどの異なる場所から提供されます。

つまり、Promise をどのように解決すればよいのでしょうか。 setTimeout 以降 ?

これは私にとってまったくクレイジーに思えましたし、それがどのように機能するのかを理解するのは本当に困難でした。実際には、それはより高いレベルで行われます。

その後、私は React Rally での Brandon Dail の素晴らしい講演を見ました。これは、React ファイバー アーキテクチャによって提供された新しいタイム スライシング機能とサスペンス機能を示しています。

Dail 氏によると、ファイバーは通常の JavaScript コールスタックとまったく同じで、 スタック内の各項目はファイバーと呼ばれます。 。これはフレームに依存するコールスタックとは異なります。 これは関数 (+ メタデータ) を表します。 むしろ、 ファイバーはコンポーネント (+ メタデータ) を表します。 。ファイバーを、コンポーネントの周囲にある、コンポーネントに関するすべての情報を備えた巨大なボックスとして見てみましょう。

これら 2 つの概念には重要な違いがあります。

まず、 コールスタックはネイティブ部分の駆動上に構築された機能です。 JavaScript コード 。すべての JavaScript 関数呼び出しをスタックし、それらを独自に実行することを目的としています。関数を呼び出すたびに、関数がスタックに追加されます。コールスタックがなければ、明確で詳細なエラー スタックトレースを取得できません。また、コールスタックには JavaScript コードからアクセスできないため、コールスタックを制御することは非常に困難であり、不可能ですらあります。

一方、ファイバーはファイバーのスタックのようなもので、同じ概念を表しますが、JavaScript コードで組み込まれています。 最も小さな単位は関数ではなくコンポーネントです。 実際には JavaScript ユニバースで実行されます。

ファイバー アーキテクチャが JavaScript で完全に構築されているということは、JavaScript を使用、アクセス、変更できることを意味します。標準の JavaScript を使用して作業できます。

私を間違った方向に導いたのは、React が JavaScript の内部動作を遮断する回避策を使用していると考えていたことです。 そうではありません 。ファイバーは、React コンポーネントに関する情報を所有し、そのライフサイクルと対話できる単なる JavaScript オブジェクトです。 React の内部機能に対してのみ動作します。

この考えはそうではありません fetch を指示するなど、JavaScript の動作方法を再定義します。 マイクロタスクの解決は、コールバック タスクの前に実行する必要があります。どの React メソッドを呼び出す必要があるかどうかが重要です。 さまざまなライフサイクル メソッド呼び出しの中断など、特定のコンテキストで。

おい、待って!ファイバーは React アプリのすべてを完全に制御できると言いましたか?しかし、コンポーネントはどのようにして React に何もしないように指示できるのでしょうか?

代数効果は可能ですが、JavaScript でお願いします

React は、ファイバー アーキテクチャのおかげで、コンポーネントを制御し、コンポーネントが実行されているかどうかを知ることができます。現在不足しているのは、特定のコンポーネントで何かが変更されたことを React に伝え、この変更を処理する方法です。

ここで代数効果が登場します。 ゲームに参加してください。

代数効果は JavaScript には存在しません。それらが何であるかをより高いレベルの説明で説明してみます。

代数効果は、ディスパッチャに似た、情報をどこかに送信できるようにする概念です。アイデアは、中断する特定の関数を呼び出すことです。 現在実行中の関数を正確な位置に配置して、親関数に計算を処理させます。親の計算が終了すると、情報が送信された最初の位置からプログラムを再開できます。

OCaml や Eff などの一部の言語では、これらの機能をネイティブで利用できます。実装の詳細は親のみに依存するため、これは非常に興味深い抽象化です。

JavaScript にそのような機能があれば素晴らしいと思いませんか?

React チームは、JavaScript try/catch を扱う React コンテキストで同様のアプローチを作成しました。 ブロック。 Dail 氏によれば、これは JavaScript で利用可能な概念の中で最も近いものです。

何かを投げることで、どこかの親に情報を送ることができます。情報を最初にキャッチした親は、その情報を処理し、計算を行うことができます。

例は千の言葉よりも優れています

同期 API を使用してフシギダネを取得しようとする次のコードを想像してください。 :

同期 API を使用してデータをフェッチすることは実際には一般的ではないため、このコードは奇妙である可能性があります。 customFetch の内部にジャンプしましょう 関数の実装:

ああ、待って!これは絶対にフェッチのようには見えません!この関数の目的がまったくわかりません…

さて、 コンポーネントの周囲に何かがあると想像してください。 、次のようなファイバーがあるとします。

時間をかけてコードを読んでください。

それでは、customFetch にジャンプしましょう。 実装:

前のスニペットの重要な部分は try/catch です。 ブロックします。

これらのさまざまなコード部分で何が起こっているかをまとめてみましょう。

  • Pokemon コンポーネントは customFetch を呼び出します メソッド。
  • customFetch メソッドは内部キャッシュを読み取ろうとしますが、キャッシュは空です。したがって、何か / どこかに代数効果をスローします。
  • fiber 親はその情報を取得し、処理して、データを取得します。次に、customFetch に値を設定します。 データをキャッシュします。
  • Component(args) で再レンダリングが発生します そして今度は customFetch キャッシュがいっぱいです。データは、同期 API を使用してコンポーネントで利用できるようになりました。

react-cache を見てください。 実装の詳細を確認し、さまざまなスローを確認してください。

このプロセス中に何か気になった可能性があります:render 2回呼び出されました。エラーをスローするための 1 つ - 一時停止 コンポーネントとデータ取得用のコンポーネントを再開します。 コンポーネント。 React では複数の render をトリガーしても問題ありません これは純粋な関数であるため、それ自体には副作用はありません。

待って…何? render 副作用はありませんか? DOM についてはどうですか?

反応フェーズ

React を長期間使用している場合は、何度も再レンダリングするのは良い習慣ではないということを聞いたことがあるかもしれません。ファイバー アーキテクチャが登場する前は、レンダー関数を呼び出すたびに、React が内部計算を行い、それに応じて DOM を変更していました。たとえば、これは setState を通じて render 関数を呼び出したときに発生しました。 。プロセスはインライン化されました:

setStaterender → 仮想ノードを比較 → DOM ノードを更新

繊維を扱う場合、プロセスは少し異なります。高パフォーマンスの DOM 変更を可能にするキューとバッチの概念が導入されました。

考え方は非常にシンプルです。画面は 1 秒あたり最大 60 フレーム実行できると想定しています。この仮定に基づき、利用可能な JavaScript 関数を使用すると、〜16.7 ミリ秒ごとにのみ一部の計算と DOM 変更を行うことができます。ファイバーを使用すると、React は複数の変更をキューに入れ、1 秒あたり約 60 回コミットできます。

この種の変更により、React はそれぞれの利点と特徴を持つ 3 つのフェーズに分割できるようになりました。

React キャッシュ、タイム スライシング、同期 API フェッチの詳細 _[React に関する Dan Abramov段階](https://twitter.com/dan_abramov/status/981712092611989509/photo/1?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwter m%5E981712092611989509&ref_url=https%3A%2F%2Fmedium.com%2Fmedia%2Fbda1c34a16e9f8a8e3eb244716a1da72%3FpostId%3D2a57dc9c2e6d" rel="noopener" target="blank" title=")

  • レンダリング フェーズは純粋で決定的です。副作用はなく、構成されているさまざまな関数を複数回呼び出すことができます。 レンダリング フェーズは中断可能です。 — render ではありません 一時停止モードにある関数ですが、フェーズ全体
  • プリコミット フレーズは、スクロールバーの位置など、読み取りモードで実際の DOM 状態にアクセスできるようにすることを目的としています。
  • コミットフェーズは実際に DOM を変更するものであり、中断することはできません 。 React はそのフェーズ中に一時停止できません。

この 3 つのフェーズのセットでは、タイム スライシング機能が導入されました。 React は、2 つのコンポーネント関数呼び出しの間のレンダリング フェーズ中に一時停止し、必要に応じてそのフェーズを再開できます。

ファイバーでは、render 利用可能な最新の表現を取得することのみを目的としています。 コンポーネントの内部状態に基づいて比較を行い、React が DOM を変更する必要があるかどうかを確認します。コミットの変更が必要な場合は、その変更が「進行中の作業」キューに追加されます。

React チームは、React Concurrent (タイム スライシング + サスペンス) とファイバー アーキテクチャのおかげでパフォーマンスを大幅に向上させました。イベントの優先順位付けや同時実行性など、さまざまなブラウザの問題に対処するための回避策を作成しました。

私たちが一歩下がってみれば、それが彼らが示したものではないでしょうか?優先順位付けは、ブラウザとフロントエンド フレームワークにとっての新たな課題のようです。

他のチームも実際の最先端技術の向上に取り組んでおり、将来の API を提案することさえあります。これが Google の見解です。

無料でコーディングを学びましょう。 freeCodeCamp のオープンソース カリキュラムは、40,000 人以上の人々が開発者としての職に就くのに役立ちました。始めましょう


  1. Chrome、Firefox、Edge、Brave、Safariですべてのタブをブックマークする方法

    学校や職場のトピックを調査する場合、多数のブラウザタブが開いてしまう可能性があります。後で参照するためにこれらのタブが必要になる場合は、新しいフォルダを作成し、開いているすべてのタブを1つずつブックマークするのに時間がかかる場合があります。 この記事では、すべてのタブをブックマークして、数回クリックするだけで新しく作成されたフォルダに追加することで、プロセスを合理化する方法を紹介します。 GoogleChromeですべてのタブをブックマークする方法 Chromeにはタブ管理用の拡張機能がたくさんありますが、開いているすべてのタブを使用しなくてもブックマークできます。 Google Chro

  2. Google Chrome のスクリーンショット ツールを有効にする方法

    スクリーンショット ツールは、Google Chrome にはない一般的なブラウザ機能の 1 つです。この機能を使用すると、ユーザーはブラウザーのスクリーンショット機能を使用して Web ページのスクリーンショットを撮ることができます。 Google の主力ブラウザである Chrome には現在、完全に機能するスナップ ツールはありませんが、今年、つまり 2022 年には実験的なスクリーンショット機能が含まれていました。 Chrome の 2 つの実験的なスクリーンショット機能のユーザーは、ブラウザ内で写真を撮ったり変更したりできます。それらはまだ標準機能ではありませんが、かなり効果的に機能