A Bridge egy architekturális komponens a React Native-ban, amely aszinkron kommunikációt biztosít a JavaScript szál és az iOS és Android natív környezete között. Sorosított JSON üzeneteket továbbít egy soron keresztül, lehetővé téve natív API-k meghívását JS kódból. A Meta, 2024 adatai szerint a Bridge továbbra is a meglévő alkalmazások alapja marad, bár teljesítményben elmarad a JSI-n alapuló új architektúrától.
Főbb pontok
Bridge (Híd) — a React Native egyik kulcsfontosságú architekturális eleme, amely kétirányú aszinkron kommunikációt biztosít a JavaScript szál, ahol az alkalmazás üzleti logikája fut, és az iOS és Android natív szálai között. A React Native 2015-ös megjelenése óta a Bridge maradt az egyetlen módja a JS kód platform API-kkal — kamera, geolokáció, fájlrendszer, értesítések és egyéb natív képességek — való interakciójának.
A Bridge architektúra az üzenetsor (message queue) elvén alapul. Amikor a JavaScript kód meghív egy natív metódust, a kérés egy JSON stringgé serializálódik, egy sorba kerül, és aszinkron módon elküldésre kerül a natív oldalra. A natív kód feldolgozza a kérést, végrehajtja a megfelelő műveletet, és az eredményt ugyanazon a soron keresztül visszaküldi a JS szálnak. A Meta React Conf 2021-es jelentése szerint egy átlagos alkalmazásban akár 10 000 üzenet is áthalad a Bridge-en másodpercenként.
A Bridge működésében részt vevő fő szálak: JavaScript Thread (JS kód végrehajtása), Native Thread (natív műveletek végrehajtása) és Shadow Thread (elrendezés kiszámítása Yoga segítségével). Minden szál függetlenül működik, ami biztosítja a felület reszponzivitását — a natív animációkat nem blokkolják a JS számítások.
A Bridge három kulcsfontosságú mechanizmust használ a kommunikációhoz: MessageQueue, JSON serializáció és üzenetek kötegelése. A MessageQueue a React Native belső komponense, amely kezeli a hívások sorát a JS és a natív oldal között. Minden natív metódushívás sorba kerül, serializálódik, és teljesítményoptimalizálás céljából kötegekben kerül elküldésre.
A MessageQueue a kötegelés elvén működik: a natív metódushívások felhalmozódnak, és 5–15 ezredmásodpercenként egy csoportban (batch) kerülnek elküldésre. Ez csökkenti a serializációs többletterhelést, mivel több hívás egy JSON csomagba van csomagolva. A natív oldalon az üzenetek deserializálódnak és elosztásra kerülnek a megfelelő modulokhoz.
A natív modulok automatikusan regisztrálódnak makrók vagy annotációk segítségével. iOS-en a RCT_EXPORT_MODULE makró, Androidon a @ReactMethod annotáció használatos. A React Native az alkalmazás indításakor beolvassa a regisztrált modulokat, és elkészíti az összes elérhető metódus konfigurációs JSON térképét. Ez a térkép átkerül a JS környezetbe, és a JavaScript megtudja, mely metódusok hívhatók meg.
Az adatok a következő úton haladnak: a JavaScript meghívja a NativeModules.CalendarModule.createCalendarEvent() függvényt. A metódus serializálódik egy JSON üzenetté modulazonosítóval, metódusnévvel és argumentumokkal. Az üzenet bekerül a MessageQueue sorba. A natív szálon az üzenet deserializálódik és továbbításra kerül a megfelelő modulhoz. A végrehajtás eredménye visszaserializálódik és Promise vagy callback formájában elküldésre kerül a JS szálba.
// Natív modul hívása JavaScript-ből Bridge-en keresztül
import { NativeModules } from 'react-native';
const CalendarModule = NativeModules.CalendarModule;
CalendarModule.createCalendarEvent('Test Event', 'Office')
.then(eventId => {
console.log('Esemény létrehozva id-vel:', eventId);
})
.catch(error => {
console.error('Sikertelen:', error);
});
A natív iOS oldalon a modul egy Objective-C osztályként jelenik meg a RCT_EXPORT_MODULE makróval. A metódus az RCT_EXPORT_METHOD makróval exportálódik, és a React Native automatikusan regisztrálja a Bridge-ben. Az argumentumok pozíció szerint kerülnek átadásra, és meg kell felelniük a támogatott JSON típusoknak: NSString, NSNumber, NSArray, NSDictionary, BOOL.
// iOS natív modul regisztrációja Bridge-ben
@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
A Bridge számos alapvető teljesítménykorláttal rendelkezik. A fő ezek közül a kötelező aszinkronitás és serializáció. Minden natív metódushívás JSON stringgé alakítja az adatokat, ami késleltetést ad hozzá és memóriát fogyaszt. Nagy adatmennyiségekkel végzett műveleteknél, mint a képek feldolgozása vagy a videóval való munka, ez szűk keresztmetszetté válik.
A JSON serializáció és deserializáció processzoridőt és memóriát igényel. Minden üzenetet stringgé kell alakítani a JS oldalon, át kell küldeni a hídon, és elemezni kell a natív oldalon. A Callstack (2022) tesztjei szerint egy 10 000 számból álló tömb serializációja a Bridge-en keresztül körülbelül 30–50 ezredmásodpercet vesz igénybe, ami elfogadhatatlan a nagy frekvenciájú hívásoknál.
A Bridge nincs optimalizálva nagy bináris adatok küldésére. A fényképek, hangfájlok és videó stream-ek alternatív megközelítéseket igényelnek — például a fájl lemezre írását és az elérési út stringként való elküldését. Ez további többletterhelést jelent a fájlrendszer olvasásához és írásához.
E korlátok felismerése vezette a Meta csapatát a React Native új architektúrájának kifejlesztéséhez, amelyben a Bridge-t JSI (JavaScript Interface) és Turbo Module váltja fel. A JSI lehetővé teszi a natív metódusok közvetlen, serializáció nélküli meghívását, ami kiküszöböli a Bridge fő hátrányát.
A Bridge és a Turbo Module összehasonlítása alapvető különbségeket mutat az architekturális megközelítésekben. A Bridge aszinkron üzenetsort használ JSON serializációval, míg a Turbo Module a JSI-n — egy közvetlen interfészen a JavaScript és a C++ között — keresztül működik, amely lehetővé teszi a natív metódusok szinkron meghívását adatkonverzió nélkül.
| Jellemző | Bridge | Turbo Module |
|---|---|---|
| Hívás típusa | Aszinkron | Szinkron és aszinkron |
| Serializáció | JSON minden hívásnál | JSI objektumok másolás nélkül |
| Teljesítmény | Közepes | Magas |
| Típusosság | Dinamikus | Statikus (Codegen) |
| Betöltés | Minden modul indításkor | Lusta (igény szerint) |
A Bridge és a Turbo Module közötti választás a React Native verziójától függ. A React Native 0.72 és régebbi verzióit használó projekteknél a Bridge marad a fő mechanizmus. A React Native 0.73-tól kezdve a Metro és az új architektúra párhuzamosan támogatott, lehetővé téve a fokozatos migrációt. A teljes átállás a Turbo Module-re a React Native 0.76+-ra való frissítést és az új architektúra konfigurációs bekapcsolását igényli.
Nézzük meg egy Native Module létrehozásának és használatának teljes ciklusát a Bridge-en keresztül egy naptárkezelő modul példáján. A modul létrehoz egy eseményt és visszaadja annak azonosítóját. Ez a példa mindkét platform — iOS és Android — beállítását lefedi.
Androidon a Native Module egy Java osztályként jön létre, amely a ReactContextBaseJavaModule osztályból származik. A @ReactMethod annotáció exportálja a metódust a Bridge-be. A Promise-hoz a com.facebook.react.bridge Promise interfésze használatos.
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());
}
}
}
A modul a @ReactModule annotáción keresztül vagy manuálisan az alkalmazás csomagjában regisztrálódik. A React Native automatikusan érzékeli és hozzáadja a Bridge-hez. A regisztráció után a modul elérhető a JavaScript-ből a NativeModules segítségével.
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();
}
}
Fontos megjegyezni, hogy a Bridge az alkalmazás újraindítását igényli új modulok hozzáadásakor, mivel a konfigurációs térkép egyszer kerül felépítésre az inicializáláskor. Ez különbözteti meg a Turbo Module-től, amely lustán töltődik be és támogatja a modulok újraindítás nélküli hot-reload-ját.
Gyakran Ismételt Kérdések
A Bridge mindig aszinkron sort és JSON serializációt használ, míg a JSI-n keresztüli közvetlen átvitel szinkron módon, adatmásolás nélkül működik. A Bridge késleltetést hoz létre a serializáció miatt, de biztosítja a szálak elkülönítését.
Nem, a Bridge csak aszinkron hívásokat támogat. A szinkron interakcióhoz az új architektúra szükséges JSI-vel és Turbo Module-lel. Ez az egyik kulcsfontosságú korlát, amely a React Native 0.76+-ban megoldásra került.
A Bridge a JSON-ba serializálható típusokat támogatja: stringek, számok, logikai értékek, tömbök, szótárak (objektumok). A bináris adatokat, például képeket, a fájlrendszeren vagy base64 kódoláson keresztül kell továbbítani.
A méréshez használja a React DevTools-t és a React Native profilert. A Performance fül mutatja a Bridge sorban lévő üzenetek számát és a késleltetéseket. Emellett elérhető a react-native-bridge-spy csomag a forgalom monitorozásához.
Az áttérés javasolt a nagy teljesítményt igénylő projekteknél vagy új alkalmazások létrehozásakor a React Native 0.76+-on. Meglévő projektek esetén a migráció lehet fokozatos — mindkét architektúra párhuzamosan működik.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is