JSI (JavaScript Interface) ist eine Softwareschicht in React Native, die direkten synchronen Zugriff von JavaScript auf C++-Objekte und -Funktionen bietet und die asynchrone JSON-Brücke Bridge ersetzt. Im Gegensatz zu seinem Vorgänger ermöglicht JSI das Aufrufen nativer Methoden ohne Nachrichtenserialisierung und das direkte Übergeben von Referenzen auf C++-Objekte in die JS-Umgebung. Laut React Native Team (2025) bietet JSI eine bis zu 10-fache Beschleunigung der JS-nativen Code-Interaktion in datenintensiven Szenarien.
Wichtige Punkte
JSI (JavaScript Interface) ist eine C++-Schicht, die der JavaScript-Engine (Hermes, JavaScriptCore, V8) die Möglichkeit gibt, direkt auf C++-Objekte, -Funktionen und -Speicher zuzugreifen. Im Gegensatz zu Bridge, das Aufrufe in JSON serialisierte und durch eine asynchrone Warteschlange leitete, ermöglicht JSI JS-Code, synchron C++-Methoden aufzurufen und sofort das Ergebnis zu erhalten.
JSI wurde in React Native 0.64 als Teil der neuen Architektur eingeführt. Das Hauptziel war die Beseitigung des Engpasses, den Bridge darstellte: Jede Interaktion zwischen JS und nativem Code verbrauchte Zeit für Serialisierung, Deserialisierung und Durchlaufen der Nachrichtenwarteschlange. JSI löst dieses Problem, indem es der JS-Engine direkten Zugriff auf C++-Objekte über Wrapper gibt, die die Schnittstellen jsi::Value, jsi::Object und jsi::Function implementieren.
JSI ist kein eins-zu-eins-Ersatz für Bridge — es ist ein grundlegend anderer Ansatz für die Integration. Bridge funktionierte wie ein Briefkasten: JS sendete eine Nachricht, sie durchlief eine Warteschlange, die native Seite verarbeitete sie und sendete eine Antwort. JSI funktioniert wie ein Zeiger: JS erhält eine Referenz auf ein C++-Objekt und kann seine Methoden synchron wie normale JS-Funktionen aufrufen. Dies ist ein grundlegender Unterschied in der Architektur der Interaktion zwischen zwei Umgebungen.
Die Notwendigkeit für JSI ergab sich aus den Einschränkungen der ursprünglichen Bridge, die in React Native 2015 etabliert wurde. Mit wachsender Beliebtheit des Frameworks und zunehmender Komplexität der Anwendungen wurde das Leistungsproblem offensichtlich: Jeder native Modulaufruf erforderte mindestens 3–5 ms für die Serialisierung. Für einfache Operationen wie das Lesen eines Sensorwerts oder das Abrufen der Bildschirmgröße war dies akzeptabel, aber für Animationen, Grafikverarbeitung und Streaming-Datenverarbeitung war es kritisch. Das React Native-Team begann 2019 mit der Arbeit an der neuen Architektur, und JSI wurde zu deren Fundament.
JSI ist als Abstraktionsschicht über JavaScript-Engines konzipiert. Es bietet eine einheitliche C++-API, die für jede spezifische Engine implementiert wird: Hermes, JavaScriptCore (iOS), V8 (Android). Das bedeutet, dass Entwickler sich nicht um Unterschiede zwischen den Engines kümmern müssen — Fabric und TurboModules funktionieren unabhängig davon, welche JS-Engine unter der Haube verwendet wird, gleich.
Im Kern von JSI steht das Konzept der Host-Objekte — C++-Objekte, die als native JS-Objekte in die JS-Umgebung exportiert werden. Wenn JS-Code auf eine Eigenschaft oder Methode eines solchen Objekts zugreift, fängt JSI den Aufruf ab und delegiert ihn an die entsprechende C++-Methode. Dies geschieht synchron, im selben Thread, ohne Kontextwechsel und ohne Speicherzuweisung für einen JSON-String.
Jedes Host-Objekt implementiert die Schnittstelle jsi::HostObject mit den Methoden get, set und getPropertyNames. Die JS-Engine ruft diese Methoden jedes Mal auf, wenn auf eine Eigenschaft des Objekts zugegriffen wird. Beispielsweise wandelt JSI beim Aufruf von NativeModule.someMethod() in JS diesen Aufruf in einen C++-Aufruf der entsprechenden Host-Objekt-Methode um. Der Rückgabewert wird als jsi::Value an JS zurückgegeben — ein generischer Typ, der eine Zahl, Zeichenkette, booleschen Wert, ein Objekt oder undefined darstellen kann.
Ein wichtiges Merkmal von JSI ist das Fehlen einer Nachrichtenwarteschlange. Bridge verwendete eine asynchrone Warteschlange: JS sendete eine Anfrage, wechselte zu anderen Aufgaben, die native Seite verarbeitete die Anfrage, und das Ergebnis wurde über einen Callback zurückgegeben. JSI arbeitet synchron: Wenn JS eine native Modulmethode über JSI aufruft, wird die Ausführung des JS-Codes angehalten, bis das Ergebnis empfangen wird. Dies vereinfacht die Logik (kein Warten auf Callbacks) und eliminiert Race Conditions, erfordert aber Vorsicht — lange synchrone Aufrufe blockieren den JS-Thread.
Über JSI erstellte Werte leben in der Laufzeitumgebung der JS-Engine und werden vom Garbage Collector verwaltet. Wenn C++-Code ein jsi::String oder jsi::Object erstellt und an JS zurückgibt, verwaltet die Umgebung automatisch den Speicher. Wenn C++-Code eine Referenz auf einen JS-Wert zwischen Aufrufen behalten möchte, wird jsi::Value::getWeak() oder ein globales jsi::Object::setProperty mit einer im Root-Objekt der Laufzeitumgebung gespeicherten Referenz verwendet. Dies verhindert eine vorzeitige Löschung durch den Garbage Collector.
JSI ist standardmäßig nicht threadsicher. Alle JSI-Methodenaufrufe müssen von dem Thread aus erfolgen, in dem JS ausgeführt wird (normalerweise der JS-Thread von React Native). Wenn ein natives Modul Hintergrundarbeit in einem separaten Thread startet, muss das Ergebnis über den JS-Thread mithilfe von runOnJS aus TurboModules zurückgegeben werden. Diese Einschränkung ist der Preis für Synchronität und das Fehlen von Serialisierung.
Der Unterschied zwischen JSI und Bridge ist grundlegend und betrifft alle Aspekte der Interaktion zwischen JS und nativem Code. Bridge war asynchron, serialisierte Daten in JSON und verwendete eine Nachrichtenwarteschlange; JSI ist synchron, arbeitet mit nativen Referenzen und benötigt keine Serialisierung.
| Parameter | Bridge | JSI |
|---|---|---|
| Aufrufmodell | Asynchrone Warteschlange | Synchroner direkter Aufruf |
| Serialisierung | JSON (Serialisierung + Deserialisierung) | Keine (direkte Referenzen auf C++-Objekte) |
| Latenz | 3–10 ms pro Aufruf | 0.1–0.5 ms pro Aufruf |
| Typisierung | Dynamisch (über JSON) | Statisch (über Codegen) |
| C++-Integration | Nur über native Module (Java/ObjC) | Direkt, ohne Vermittler |
| Thread | Separater nativer Thread | JS-Thread (synchron) |
Laut React Native Team reduzierte die Migration von Bridge zu JSI in der Facebook Marketplace-App die Startzeit um 35% und verringerte den Speicherverbrauch um 20%, indem die Datenduplizierung zwischen JS und der nativen Seite beseitigt wurde.
Bridge war kein „Fehler“ — es war eine architektonische Entscheidung, die zum Zeitpunkt der Erstellung von React Native 2015 gerechtfertigt war. Die native Entwicklung für zwei Plattformen mit unterschiedlichen Sprachen erforderte ein universelles Austauschformat. JSON als Serialisierungsformat war auf allen Plattformen verfügbar und ermöglichte die Vereinheitlichung der Interaktion. Das Problem wurde später offensichtlich, als React Native für komplexe Anwendungen mit Tausenden von nativen Modulaufrufen pro Sekunde verwendet wurde.
React Native bewahrt die Abwärtskompatibilität: Für Bridge geschriebene native Module funktionieren weiterhin in der neuen Architektur über eine Kompatibilitätsschicht. Für neue Module wird jedoch empfohlen, JSI direkt über TurboModules zu verwenden. Die Migration bestehender Module beinhaltet das Ersetzen des Interaktionsprotokolls, ohne die Geschäftslogik des Moduls selbst zu ändern.
JSI ist eine grundlegende Schicht, auf der alle Komponenten der neuen React Native-Architektur aufbauen. Ohne JSI wären weder Fabric (der neue Renderer) noch TurboModules (optimierte native Module) möglich. JSI bietet eine einheitliche Möglichkeit für JS, auf allen Ebenen mit C++ zu interagieren.
Fabric ist der neue React Native-Renderer, der JSI für den synchronen Zugriff auf C++-UI-Darstellungen verwendet. In der alten Architektur erfolgte das Rendern über Bridge: JS erstellte React-Elemente, serialisierte sie in JSON, sendete sie über Bridge, die native Seite deserialisierte und erstellte die UI. Fabric erstellt über JSI direkt aus JS C++-Shadow-Tree-Objekte, berechnet synchron das Layout über Yoga und übergibt fertige Frames an den nativen Renderer — ohne eine einzige Serialisierung.
TurboModules sind die Evolution der nativen React Native-Module. Anstatt ein Modul in Bridge zu registrieren und seine Methoden über JSON aufzurufen, verwendet TurboModules JSI für verzögertes Laden und direkte Aufrufe. Wenn JS-Code zum ersten Mal auf ein Modul zugreift, erstellt JSI ein Host-Objekt — es lädt das native Modul und stellt seine Methoden als C++-Funktionen zur Verfügung. Verzögertes Laden bedeutet, dass das Modul bis zum ersten Zugriff keinen Speicher verbraucht — dies ist besonders wichtig für Anwendungen mit Dutzenden von nativen Modulen, von denen viele nur in bestimmten Bildschirmen verwendet werden.
Für die Arbeit mit JSI in der neuen Architektur wird Codegen verwendet — ein Tool, das C++-Bindungen aus JavaScript-Spezifikationen generiert. Der Entwickler beschreibt die native Modulschnittstelle in TypeScript oder Flow, und Codegen generiert C++-Code, der ein JSI-kompatibles Host-Objekt implementiert. Dies automatisiert die Routinearbeit und garantiert, dass die Typen auf der JS- und C++-Seite synchronisiert sind.
Schauen wir uns an, wie die Arbeit mit JSI in der Praxis aussieht. In diesem Beispiel erstellen wir eine einfache C++-Klasse, die über JSI nach JS exportiert wird, und rufen ihre Methode aus JavaScript-Code in React Native auf.
// Calculator.h — C++-Klassenheader, zugänglich von JS
class Calculator {
public:
double add(double a, double b) { return a + b; }
double multiply(double a, double b) { return a * b; }
};
Die Calculator-Klasse enthält zwei arithmetische Methoden. Wir müssen sie von JS aus zugänglich machen. Dazu wird ein Host-Objekt erstellt, das Calculator umschließt und seine Methoden über JSI bereitstellt.
// CalculatorHostObject.cpp — JSI-Wrapper-Implementierung
class CalculatorHostObject : public jsi::HostObject {
private:
Calculator calc;
public:
jsi::Value get(jsi::Runtime& runtime,
const jsi::PropNameID& name) override {
auto propName = name.utf8(runtime);
if (propName == "add") {
return jsi::Function::createFromHostFunction(
runtime, name, 2,
[this](jsi::Runtime& runtime,
const jsi::Value& thisVal,
const jsi::Value* args,
size_t count) -> jsi::Value {
return jsi::Value(calc.add(
args[0].asNumber(),
args[1].asNumber()));
});
}
return jsi::Value::undefined();
}
};
In diesem Code wird die get-Methode jedes Mal aufgerufen, wenn JS auf eine Eigenschaft des Objekts zugreift. Wenn der Eigenschaftsname „add“ lautet, wird eine C++-Funktion zurückgegeben, die zwei Argumente von JS entgegennimmt und calc.add() aufruft. Der Wert wird als jsi::Value zurückgegeben — JSI konvertiert automatisch double in eine JS-Zahl.
Nach der Registrierung des Host-Objekts in der JS-Umgebung sieht der Aufruf wie eine normale JS-Funktion aus. Alle Typen werden in der Codegenerierungsphase überprüft, wodurch Typkonfliktfehler zur Laufzeit ausgeschlossen werden.
// JavaScript — Aufruf des C++-Taschenrechners über JSI
import { Calculator } from 'react-native-calculator'
const result = Calculator.add(5, 3)
console.log(result) // 8 — synchron, keine Verzögerung
const product = Calculator.multiply(4, 2.5)
console.log(product) // 10 — sofortiges Ergebnis
Hinweis: Das Ergebnis wird sofort zurückgegeben, ohne Promise, ohne await, ohne Callbacks. Dies ist ein synchroner Aufruf, der in der Bridge-Architektur unmöglich war. Für langlebige Operationen (Dateilesen, Netzwerkanfrage) sollten asynchrone Muster verwendet werden — JSI beseitigt nicht die Notwendigkeit von Hintergrundthreads für schwere Aufgaben.
In der Praxis schreiben die meisten Entwickler JSI-Host-Objekte nicht manuell — diese Arbeit erledigt Codegen, das C++-Wrapper auf Basis von TypeScript-Spezifikationen generiert. Das Verständnis der Funktionsweise von JSI im Inneren ist jedoch für effektives Leistungsdebugging und bei der Erstellung komplexer nativer Module erforderlich, die direkten Zugriff auf C++-Bibliotheken (Skia, FFmpeg, OpenCV) benötigen.
Häufig gestellte Fragen
Bridge arbeitet asynchron über JSON-Serialisierung und eine Nachrichtenwarteschlange — jeder Aufruf benötigt 3–10 ms für die Datenkonvertierung. JSI bietet synchronen direkten Zugriff auf C++-Objekte ohne Serialisierung und reduziert die Latenz auf 0.1–0.5 ms. JSI unterstützt auch die Übergabe von Objektreferenzen anstelle von Kopien.
Ja, JSI bietet eine einheitliche C++-API, die für Hermes (React Native-Standard), JavaScriptCore (iOS) und V8 (Android) implementiert ist. Entwickler müssen keinen unterschiedlichen Code für verschiedene Engines schreiben — Fabric und TurboModules funktionieren auf allen unterstützten Engines identisch.
Ja, React Native bietet eine Abwärtskompatibilitätsschicht. Für Bridge geschriebene native Module funktionieren weiterhin in der neuen Architektur. Es wird jedoch empfohlen, sie auf TurboModules zu migrieren, um die Vorteile von JSI zu nutzen — verzögertes Laden und synchrone Aufrufe.
Für die tägliche Entwicklung — nein. TypeScript-Spezifikationen nativer Module werden über Codegen automatisch in C++-Bindungen kompiliert. C++-Kenntnisse werden nur beim Erstellen eigener C++-Bibliotheken oder beim Debuggen der JSI-Leistung auf Runtime-Ebene benötigt.
JSI löst drei Hauptprobleme von Bridge: hohe Latenz aufgrund von JSON-Serialisierung, fehlende synchrone Aufrufe und die Unmöglichkeit, komplexe Objekte per Referenz zu übergeben. JSI ermöglicht auch die direkte Integration von C++-Bibliotheken ohne Java- oder Objective-C-Zwischenschicht.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch