Bridge — is een architectuurcomponent van React Native die asynchrone communicatie mogelijk maakt tussen de JavaScript-thread en de native omgeving van iOS en Android. Het verzendt geserialiseerde JSON-berichten via een wachtrij, waardoor native API's vanuit JS-code kunnen worden aangeroepen. Volgens Meta, 2024, blijft Bridge de basis van bestaande applicaties, hoewel het qua prestaties onderdoet voor de nieuwe architectuur op basis van JSI.
Belangrijkste punten
Bridge (Brug) — is een belangrijk architectuurelement van React Native dat tweerichtings asynchrone communicatie mogelijk maakt tussen de JavaScript-thread, waarin de bedrijfslogica van de applicatie wordt uitgevoerd, en de native threads van iOS en Android. Sinds de release van React Native in 2015 is Bridge de enige manier geweest voor JS-code om te communiceren met platform-API's — camera, geolocatie, bestandssysteem, meldingen en andere native mogelijkheden.
De Bridge-architectuur is gebaseerd op het principe van een berichtenwachtrij (message queue). Wanneer JavaScript-code een native methode aanroept, wordt het verzoek geserialiseerd naar een JSON-string, in een wachtrij geplaatst en asynchroon naar de native kant verzonden. Native code verwerkt het verzoek, voert de bijbehorende bewerking uit en stuurt het resultaat terug via dezelfde wachtrij naar de JS-thread. Volgens het rapport van Meta op React Conf 2021, passeren er tot 10.000 berichten per seconde door Bridge in een gemiddelde applicatie.
De belangrijkste threads die betrokken zijn bij Bridge: JavaScript Thread (uitvoering van JS-code), Native Thread (uitvoering van native bewerkingen) en Shadow Thread (berekening van de lay-out met Yoga). Elke thread werkt onafhankelijk, wat zorgt voor responsiviteit van de interface — native animaties worden niet geblokkeerd door JS-berekeningen.
Bridge gebruikt drie belangrijke mechanismen voor communicatie: MessageQueue, JSON-serialisatie en het bundelen van berichten. MessageQueue is een interne component van React Native die de wachtrij van aanroepen tussen JS en de native kant beheert. Elke aanroep van een native methode wordt in de wachtrij geplaatst, geserialiseerd en in batches verzonden voor prestatieoptimalisatie.
MessageQueue werkt op basis van bundeling: aanroepen van native methoden worden verzameld en elke 5–15 milliseconden als één groep (batch) verzonden. Dit vermindert de serialisatieoverhead, omdat meerdere aanroepen in één JSON-pakket worden verpakt. Aan de native kant worden berichten gedeserialiseerd en verdeeld over de bijbehorende modules.
Native modules worden automatisch geregistreerd via macro's of annotaties. Op iOS wordt de macro RCT_EXPORT_MODULE gebruikt, op Android de annotatie @ReactMethod. React Native scant de geregistreerde modules bij het opstarten van de applicatie en bouwt een configuratie-JSON-kaart van alle beschikbare methoden. Deze kaart wordt naar de JS-omgeving gestuurd en JavaScript weet welke methoden kunnen worden aangeroepen.
Gegevens doorlopen het volgende pad: JavaScript roept NativeModules.CalendarModule.createCalendarEvent() aan. De methode wordt geserialiseerd naar een JSON-bericht met module-ID, methodenaam en argumenten. Het bericht komt in de MessageQueue-wachtrij. In de native thread wordt het bericht gedeserialiseerd en doorgegeven aan de bijbehorende module. Het resultaat van de uitvoering wordt teruggeserialiseerd en als Promise of callback naar de JS-thread gestuurd.
// Native module aanroep vanuit JavaScript via Bridge
import { NativeModules } from 'react-native';
const CalendarModule = NativeModules.CalendarModule;
CalendarModule.createCalendarEvent('Test Event', 'Office')
.then(eventId => {
console.log('Gebeurtenis gemaakt met id:', eventId);
})
.catch(error => {
console.error('Mislukt:', error);
});
Aan de native kant van iOS ziet de module eruit als een Objective-C-klasse met de macro RCT_EXPORT_MODULE. De methode wordt geëxporteerd met de macro RCT_EXPORT_METHOD en React Native registreert deze automatisch in Bridge. Argumenten worden op positie doorgegeven en moeten overeenkomen met de ondersteunde JSON-typen: NSString, NSNumber, NSArray, NSDictionary, BOOL.
// iOS Native Module registratie in Bridge
@interface CalendarModule () RCT_EXPORT_MODULE()
@end
@implementation CalendarModule
RCT_EXPORT_METHOD(createCalendarEvent:(NSString *)name
location:(NSString *)location
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSNumber *eventId = createEvent(name, location);
resolve(eventId);
}
@end
Bridge heeft een aantal fundamentele prestatiebeperkingen. De belangrijkste is de verplichte asynchroniteit en serialisatie. Elke aanroep van een native methode zet gegevens om in een JSON-string, wat vertraging toevoegt en geheugen verbruikt. Voor bewerkingen met grote hoeveelheden gegevens, zoals beeldverwerking of werken met video, wordt dit een knelpunt.
JSON-serialisatie en -deserialisatie kosten processortijd en geheugen. Elk bericht moet aan de JS-kant naar een string worden omgezet, via de brug worden verzonden en aan de native kant worden geparseerd. Volgens tests van Callstack (2022) duurt serialisatie van een array van 10.000 getallen via Bridge ongeveer 30–50 milliseconden, wat onaanvaardbaar is voor hoogfrequente aanroepen.
Bridge is niet geoptimaliseerd voor het verzenden van grote binaire gegevens. Foto's, audiobestanden en videostreams vereisen alternatieve benaderingen — bijvoorbeeld het wegschrijven van een bestand naar schijf en het verzenden van het pad als string. Dit creëert extra overhead voor het lezen en schrijven van het bestandssysteem.
Het besef van deze beperkingen heeft het Meta-team ertoe gebracht een nieuwe React Native-architectuur te ontwikkelen, waarin Bridge wordt vervangen door JSI (JavaScript Interface) en Turbo Module. JSI maakt directe aanroep van native methoden zonder serialisatie mogelijk, wat het grootste nadeel van Bridge wegneemt.
De vergelijking van Bridge en Turbo Module toont fundamentele verschillen in architecturale benaderingen. Bridge gebruikt een asynchrone berichtenwachtrij met JSON-serialisatie, terwijl Turbo Module werkt via JSI — een directe interface tussen JavaScript en C++ die synchrone aanroep van native methoden zonder gegevensconversie mogelijk maakt.
| Kenmerk | Bridge | Turbo Module |
|---|---|---|
| Aanroeptype | Asynchroon | Synchroon en asynchroon |
| Serialisatie | JSON bij elke aanroep | JSI-objecten zonder kopiëren |
| Prestaties | Gemiddeld | Hoog |
| Typering | Dynamisch | Statisch (Codegen) |
| Laden | Alle modules bij opstarten | Lui (op aanvraag) |
De keuze tussen Bridge en Turbo Module hangt af van de React Native-versie. Voor projecten op React Native 0.72 en ouder blijft Bridge het belangrijkste mechanisme. Vanaf React Native 0.73 worden Metro en de nieuwe architectuur parallel ondersteund, wat geleidelijke migratie mogelijk maakt. Volledige overgang naar Turbo Module vereist een upgrade naar React Native 0.76+ en het inschakelen van de nieuwe architectuur in de configuratie.
Laten we de volledige cyclus van het maken en gebruiken van een Native Module via Bridge bekijken aan de hand van een module voor het werken met een agenda. De module maakt een gebeurtenis aan en retourneert de identificatie ervan. Dit voorbeeld omvat de configuratie voor beide platforms — iOS en Android.
Op Android wordt Native Module gemaakt als een Java-klasse die overerft van ReactContextBaseJavaModule. De annotatie @ReactMethod exporteert de methode naar Bridge. Voor Promise wordt de Promise-interface van com.facebook.react.bridge gebruikt.
public class CalendarModule extends ReactContextBaseJavaModule {
@Override
public String getName() {
return "CalendarModule";
}
@ReactMethod
public void createCalendarEvent(
String name,
String location,
Promise promise) {
try {
Integer eventId = createCalendarEventNative(name, location);
promise.resolve(eventId);
} catch (Exception e) {
promise.reject("EVENT_ERROR", e.getMessage());
}
}
}
De module wordt geregistreerd via @ReactModule of handmatig in het applicatiepakket. React Native detecteert deze automatisch en voegt deze toe aan Bridge. Na registratie is de module toegankelijk vanuit JavaScript via NativeModules.
public class CalendarPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
return Arrays.asList(
new CalendarModule(reactContext)
);
}
@Override
public List<ViewManager> createViewManagers(
ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Het is belangrijk op te merken dat Bridge herstart van de applicatie vereist bij het toevoegen van nieuwe modules, omdat de configuratiekaart eenmalig wordt gebouwd tijdens initialisatie. Dit onderscheidt het van Turbo Module, die lui wordt geladen en hot-reload van modules ondersteunt zonder herstart.
Veelgestelde vragen
Bridge gebruikt altijd een asynchrone wachtrij en JSON-serialisatie, terwijl directe overdracht via JSI synchroon en zonder gegevenskopiëren werkt. Bridge creëert vertraging door serialisatie, maar zorgt voor isolatie van threads.
Nee, Bridge ondersteunt alleen asynchrone aanroepen. Voor synchrone interactie is de nieuwe architectuur met JSI en Turbo Module vereist. Dit is een van de belangrijkste beperkingen die is opgelost in React Native 0.76+.
Bridge ondersteunt typen die serialiseerbaar zijn naar JSON: strings, getallen, booleans, arrays, dictionaries (objecten). Binaire gegevens zoals afbeeldingen moeten via het bestandssysteem of base64-codering worden verzonden.
Gebruik React DevTools en de React Native-profiler voor het meten. Het tabblad Performance toont het aantal berichten in de Bridge-wachtrij en vertragingen. Ook is het pakket react-native-bridge-spy beschikbaar voor verkeersmonitoring.
Overstappen wordt aanbevolen voor projecten die hoge prestaties vereisen of bij het maken van nieuwe applicaties op React Native 0.76+. Voor bestaande projecten kan migratie geleidelijk zijn — beide architecturen werken parallel.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook