Javascript Interface (JSI): Übersicht und Notwendigkeit einer Neuarchitektur von React Native

Nov 26 2022
React Native ist mit mehreren Vorteilen wie plattformübergreifender Unterstützung, OTA-Updates, Live-Neuladen, Kosteneffizienz usw. gebündelt, aber der größte Engpass bei der Skalierung von React-nativen Anwendungen war die Leistung, wenn Sie weitere Module hinzufügen, wenn die Anwendung datenintensiv wird oder wenn es mehrere gibt Pässe über die Brücke erforderlich. Aber wie funktioniert die aktuelle Architektur? Die Architektur von React Native hängt von drei Threads ab: a) UI-Thread: Dies ist der Hauptanwendungs-Thread, der zum Rendern von Android- und iOS-Ansichten verwendet wird.

React Native ist mit mehreren Vorteilen wie plattformübergreifender Unterstützung, OTA-Updates, Live-Neuladen, Kosteneffizienz usw. gebündelt, aber der größte Engpass bei der Skalierung von React-nativen Anwendungen war die Leistung, wenn Sie weitere Module hinzufügen, wenn die Anwendung datenintensiv wird oder wenn es mehrere gibt Pässe über die Brücke erforderlich.

Aber wie funktioniert die aktuelle Architektur?

Die Architektur von React Native hängt von drei Threads ab: a) UI-Thread: Dies ist der Hauptanwendungs-Thread, der zum Rendern von Android- und iOS-Ansichten verwendet wird. b) Shadow-Thread: Es ist eine Art Hintergrund-Thread, der das Layout der Elemente (unter Verwendung von Yoga ) vor dem Rendern auf der Host-Plattform berechnet. c) JS-Thread: Gebündeltes JS, das für die Handhabung der gesamten Logik in Ihrer reagierenden nativen Anwendung verantwortlich ist.


Quelle: FreeCodeCamp

Die Interaktion zwischen diesen Threads ist nicht direkt und jedes Mal, wenn ein Thread mit dem anderen Thread interagieren muss, muss er die schwere Aufgabe der Serialisierung und Deserialisierung von Daten in JSON durchlaufen, um über die Brücke zu gehen. Dies führt zu einer unnötigen Kopie von Daten, und diese Brücke kann ziemlich leicht überfüllt werden, da die Operationen asynchron sind und es keine strengen Typisierungen gibt.

Einige Einschränkungen der aktuellen Architektur:
1. Javascript und native Seite kennen einander nicht und verlassen sich auf asynchrone JSON-Nachrichten.
2. Alle Module werden beim Start geladen, was die Zeit bis zur Interaktion verlängert.
3. Keine Priorisierung von Aktionen: Wichtige Benutzerinteraktionen können nicht gegenüber den anderen Aktionen priorisiert werden.
4. Bridge-Serialisierung
5. UI-Elemente sind nicht direkt über den JS-Thread zugänglich.

Aktuelle Architektur von React Native

Einführung in JSI

Neue Architektur für React Native

JSI bringt eine große Veränderung in der Interaktion von Javascript und nativem Teil mit sich. Es bietet eine direkte Kommunikation zwischen den beiden Bereichen mit Hilfe einer Schnittstelle zwischen JS und C++. Mithilfe der JavaScript-Schnittstelle kann JS Verweise auf Host-Objekte halten und Methoden für sie aufrufen. Mit Hilfe des Host-Objekts können wir jetzt native Objekte im Javascript-Kontext verwenden. Die Brücke, die der größte Engpass war, ist in Teile aufgeteilt:

Stoff

Das neue von Facebook erstellte Rendering-System, das die Neuarchitektur des UI-Managers darstellt. Dieser Renderer ist in C++ implementiert und der Kern wird von Plattformen gemeinsam genutzt. In der vorherigen Implementierung umfasste die Layouterstellung mehrere Schritte wie die Serialisierung von JSON und Sprünge über die Bridge, was zu großen Problemen führte, wenn die Bridge blockiert wurde, z. B.: Frame Drops beim Scrollen durch eine unendliche Liste. Die neue Implementierung ermöglicht es dem UI-Manager, den Schattenbaum direkt in C++ zu erstellen, was die Erfahrung erheblich verbessert, indem die Anzahl der Sprünge zwischen Bereichen reduziert wird. Die Operationen sind synchron und Thread-sicher, die von React (JavaScript) in den Renderer (C++) ausgeführt werden, normalerweise auf dem JavaScript-Thread. Es erfordert auch weniger Serialisierung von Daten, da die Javascript-Werte direkt aus JSI ausgewählt werden können. Diese direkte Steuerung hilft auch bei der Priorisierung der Aktionen, der Renderer kann jetzt bestimmte Benutzerinteraktionen priorisieren, um sicherzustellen, dass sie rechtzeitig bearbeitet werden. Dadurch wird die Leistung in Listen, der Navigation und der Handhabung von Gesten erheblich verbessert.

Turbo-Module

In der vorherigen Implementierung hatten wir keinen Verweis auf die nativen Module, sodass jedes Modul beim Start geladen wurde, was die TTI (Time to Interactive) erhöht, aber mit Turbomodulen können wir die Module nach Bedarf laden, was hilfreich ist bei der Verbesserung der Startzeit. Beispiel: Wenn Sie ein Modul zum Drucken eines Dokuments über einen Link haben, könnten wir dieses Modul jetzt laden, wenn wir auf dem Druckbildschirm landen, und nicht beim Start der Anwendung, was in der vorherigen Architektur getan wurde. Die Fähigkeit, das Modul in C++ zu schreiben, trägt ebenfalls zu dem Vorteil bei, da es die doppelte Implementierung über Plattformen hinweg reduziert.

Codegen

Um dies alles zusammenzufügen und beide Realms kompatibel zu machen, hat das React Native-Team einen Type Checker entwickelt, um die Kompatibilität zwischen JS und der Native-Seite zu automatisieren. Dieses Tool heißt Codegen. Es verwendet einen modularen Ansatz, was bedeutet, dass jede statisch typisierte Javascript-Sprache unterstützt werden könnte, indem der Parser für dieses System verwendet wird. Durch die Verwendung des typisierten JavaScripts als Quelle der Wahrheit kann dieser Generator die Schnittstellendateien definieren, die von Fabric und TurboModules benötigt werden, um Nachrichten zuverlässig über die Realms zu senden. Codegen bietet auch Sicherheit beim Kompilieren, was bedeutet, dass beide Umgebungen Befehle ohne Laufzeitprüfungen ausführen können, was eine geringere Codegröße und eine schnellere Ausführung bedeutet.
Da wir jetzt C++-Code haben und C++ stark typisiert ist, erzwingen wir die Typisierung unseres JS-Codes, da wir Typen definieren müssen und nirgendwo im Code schreiben können . Es erstellt im Grunde eine Schnittstelle für Sie, und da sie jetzt generiert werden und in C++ vorliegen, können wir den gesendeten Daten grundsätzlich vertrauen und müssen die Daten nicht hin und her überprüfen. Dies bedeutet auch, dass wir mithilfe der Typprüfungen Probleme während der Entwicklungsphase leicht identifizieren können, die zu fatalen Abstürzen oder einer schlechten Benutzererfahrung geführt haben könnten.

Einige Hauptvorteile von JSI

  1. Javascript-Code kann einen Verweis auf alle nativen UI-Elemente enthalten und die Methoden darauf aufrufen (ähnlich wie bei der DOM-Manipulation im Web)
  2. Schnelle und direkte Bindungen an nativen Code, die die Leistung erheblich verbessern können, z. B. verwendet MMKV JSI, das ~ 30-mal schneller ist als Asyncstorage.
  3. Andere Engines als JavaScript Core können verwendet werden.
  4. Native Module können bei Bedarf geladen werden.
  5. Statische Typprüfung, um den JS- und nativen Code kompatibel zu machen.

React native JSI befindet sich derzeit in der experimentellen Rollout-Phase, und wenn weitere Projekte diese Änderung übernehmen, werden wir mehr über die Einschränkungen und Auswirkungen der neuen Architektur erfahren, aber eines ist sicher, die Zukunft der Entwicklung von nativen und plattformübergreifenden React-Anwendungen wirkt spannend.