メインコンテンツへ移動

React Nativeアーキテクチャの概要

無料2019-09-07#Tool#React Native Architecture#React Native架构#React Native线程模型#React Native threading model#React Native内部原理

設計やスレッドモデルなどの観点から、React Nativeの現在のアーキテクチャを紹介します。

1. アーキテクチャ設計

全体的に、Native、JavaScript、Bridgeの3つの大きな部分に分かれています:

[caption id="attachment_2013" align="alignnone" width="625"]React Native layers React Native layers[/caption]

NativeはUIの更新とインタラクションを管理し、JavaScriptはNativeの機能を呼び出してビジネスロジックを実現し、Bridgeはその両者の間でメッセージを伝達します。すなわち:

最上層ではReactのようなサポートを提供し、JavaScriptCoreが提供するJavaScriptランタイム環境で動作します。Bridge層はJavaScriptとNativeの世界を接続します。具体的には、Shadow Treeを使用してUI効果とインタラクション機能を定義し、Native ModulesがNative機能(Bluetoothなど)を提供します。両者はJSONメッセージを介して互いに通信します。

Bridge層はReact Native技術の核心であり、設計上3つの特徴を持っています:

  • 非同期(asynchronous):同期通信に依存しない。

  • シリアライズ可能(serializable):すべてのUI操作がJSONにシリアライズされ、元に戻せることを保証する。

  • バッチ処理(batched):Nativeの呼び出しをキューに入れ、一括で処理する。

UI操作を一連の命令として記述し、JSON形式のメッセージにシリアライズします:

Just as React DOM turns React state updates into imperative, mutative calls to DOM APIs like document.createElement(attrs) and .appendChild(), React Native was designed to return a single JSON message that lists mutations to perform, like [["createView", attrs], ["manageChildren", ...]].

非常に柔軟であり、この命令ベースのメカニズムにより、JSコードを別のJSエンジン上で実行することすら可能です。これがChrome debuggingです:

Chrome debugging, which runs all the JavaScript code asynchronously over a WebSocket connection.

2. スレッドモデル

React Nativeには主に以下の3つのスレッドがあります:

  • UI Thread:Android/iOS(またはその他のプラットフォーム)アプリケーションのメインスレッド。

  • Shadow Thread:レイアウト計算とUIの構築を行うスレッド。

  • JS Thread:ReactなどのJavaScriptコードを実行するスレッド。

これに加えて、Native Modulesスレッドというカテゴリがあり、異なるNative Moduleは異なるスレッドで実行される可能性があります(詳細はThreadingを参照):

[caption id="attachment_2014" align="alignnone" width="625"]React Native threading model React Native threading model[/caption]

スレッド間の相互作用の関係は以下の通りです:

P.S. 図中のqueueはGCD dispatch queueを指しており、(厳密には不正確ですが)スレッドとして簡単に理解できます。

3. 起動プロセス

時系列で見ると、App起動時にReact Nativeのランタイム環境(すなわちBridge)が初期化され、Bridgeの準備が整った後にJSの実行が始まり、最後にNativeのレンダリングが開始されます:

完全な起動プロセスは以下のようになります:

[caption id="attachment_2015" align="alignnone" width="625"]React Native App start up flow React Native App start up flow[/caption]

このうち、上半分がBridgeの初期化プロセスです:

以下の4つの部分に分かれます(これらの操作はすべて起動時に行われます):

  • JavaScriptコードのロード:開発モードではネットワークからダウンロードし、本番環境ではデバイスのストレージから読み込みます。

  • Native Modulesの初期化:Native Moduleの登録情報に基づき、すべてのNative Moduleをロードし、インスタンス化します。

  • Native Module情報の注入:Native Moduleの登録情報を取得し、グローバル変数としてJS Contextに注入します。

  • JavaScriptエンジンの初期化:すなわちJavaScriptCoreの初期化です。

Bridgeが確立された後、JavaScriptコードの実行が開始され、ユーザーインターフェースをレンダリングし、ビジネスロジックを実現します。

4. レンダリングメカニズム

[caption id="attachment_2016" align="alignnone" width="625"]React Native threads React Native threads[/caption]

JSスレッドはビュー情報(構造、スタイル、プロパティなど)をShadowスレッドに渡し、レイアウト計算用のShadow Treeを作成します。Shadowスレッドがレイアウトを計算した後、完全なビュー情報(幅、高さ、位置などを含む)をメインスレッドに渡し、メインスレッドはそれに基づいてNative Viewを作成します。

ユーザー入力に対しては、まずメインスレッドが関連情報をイベントメッセージとしてパッケージ化し、Shadowスレッドに渡します。次に、Shadow Treeが確立したマッピング関係に基づいて、対応する要素の指定されたイベントを生成します。最後に、そのイベントをJSスレッドに渡し、対応するJSのコールバック関数を実行します。すなわち:

[caption id="attachment_2017" align="alignnone" width="625"]React Native UI interaction React Native UI interaction[/caption]

これで、すべてが明確になりました。

参考資料

コメント

コメントはまだありません

コメントを書く