Το Bridge είναι ένα αρχιτεκτονικό στοιχείο του React Native που εξασφαλίζει ασύγχρονη επικοινωνία μεταξύ του νήματος JavaScript και του native περιβάλλοντος iOS και Android. Μεταφέρει σειριοποιημένα μηνύματα JSON μέσω μιας ουράς, επιτρέποντας την κλήση native API από κώδικα JS. Σύμφωνα με τα δεδομένα της Meta, 2024, το Bridge παραμένει η βάση των υπαρχουσών εφαρμογών, αν και υστερεί σε απόδοση σε σχέση με τη νέα αρχιτεκτονική που βασίζεται στο JSI.
Κύρια σημεία
Bridge (Γέφυρα) — είναι ένα βασικό αρχιτεκτονικό στοιχείο του React Native που εξασφαλίζει αμφίδρομη ασύγχρονη επικοινωνία μεταξύ του νήματος JavaScript, όπου εκτελείται η επιχειρηματική λογική της εφαρμογής, και των native νημάτων iOS και Android. Από την κυκλοφορία του React Native το 2015, το Bridge παρέμενε ο μοναδικός τρόπος αλληλεπίδρασης του κώδικα JS με τα API της πλατφόρμας — κάμερα, γεωτοποθεσία, σύστημα αρχείων, ειδοποιήσεις και άλλες native δυνατότητες.
Η αρχιτεκτονική Bridge βασίζεται στην αρχή της ουράς μηνυμάτων (message queue). Όταν ο κώδικας JavaScript καλεί μια native μέθοδο, το αίτημα σειριοποιείται σε μια συμβολοσειρά JSON, τοποθετείται σε μια ουρά και αποστέλλεται ασύγχρονα στην native πλευρά. Ο native κώδικας επεξεργάζεται το αίτημα, εκτελεί την αντίστοιχη λειτουργία και στέλνει το αποτέλεσμα πίσω μέσω της ίδιας ουράς στο νήμα JS. Σύμφωνα με την αναφορά της Meta στο React Conf 2021, έως 10.000 μηνύματα ανά δευτερόλεπτο διέρχονται μέσω του Bridge σε μια μέση εφαρμογή.
Τα κύρια νήματα που συμμετέχουν στη λειτουργία του Bridge: JavaScript Thread (εκτέλεση κώδικα JS), Native Thread (εκτέλεση native λειτουργιών) και Shadow Thread (υπολογισμός διάταξης με τη χρήση Yoga). Κάθε νήμα λειτουργεί ανεξάρτητα, εξασφαλίζοντας ανταπόκριση της διεπαφής — τα native animations δεν μπλοκάρονται από τους υπολογισμούς JS.
Το Bridge χρησιμοποιεί τρεις βασικούς μηχανισμούς για επικοινωνία: MessageQueue, σειριοποίηση JSON και ομαδοποίηση μηνυμάτων. Το MessageQueue είναι ένα εσωτερικό στοιχείο του React Native που διαχειρίζεται την ουρά κλήσεων μεταξύ JS και native πλευράς. Κάθε κλήση μιας native μεθόδου τοποθετείται στην ουρά, σειριοποιείται και αποστέλλεται σε παρτίδες για βελτιστοποίηση της απόδοσης.
Το MessageQueue λειτουργεί με βάση την αρχή της ομαδοποίησης: οι κλήσεις native μεθόδων συσσωρεύονται και αποστέλλονται ως μία ομάδα (batch) κάθε 5–15 χιλιοστά του δευτερολέπτου. Αυτό μειώνει την επιβάρυνση σειριοποίησης, καθώς πολλές κλήσεις συσκευάζονται σε ένα πακέτο JSON. Στην native πλευρά, τα μηνύματα αποσειριοποιούνται και διανέμονται στα αντίστοιχα modules.
Τα native modules εγγράφονται αυτόματα μέσω μακροεντολών ή σχολιασμών. Στο iOS χρησιμοποιείται η μακροεντολή RCT_EXPORT_MODULE, στο Android — ο σχολιασμός @ReactMethod. Το React Native σαρώνει τα εγγεγραμμένα modules κατά την εκκίνηση της εφαρμογής και χτίζει έναν χάρτη διαμόρφωσης JSON όλων των διαθέσιμων μεθόδων. Αυτός ο χάρτης μεταφέρεται στο περιβάλλον JS και η JavaScript μαθαίνει ποιες μέθοδοι μπορούν να κληθούν.
Τα δεδομένα ακολουθούν την εξής διαδρομή: Η JavaScript καλεί NativeModules.CalendarModule.createCalendarEvent(). Η μέθοδος σειριοποιείται σε ένα μήνυμα JSON με αναγνωριστικό module, όνομα μεθόδου και ορίσματα. Το μήνυμα εισέρχεται στην ουρά MessageQueue. Στο native νήμα, το μήνυμα αποσειριοποιείται και μεταβιβάζεται στο αντίστοιχο module. Το αποτέλεσμα εκτέλεσης σειριοποιείται ξανά και αποστέλλεται στο νήμα JS ως Promise ή callback.
// Κλήση native module από JavaScript μέσω Bridge
import { NativeModules } from 'react-native';
const CalendarModule = NativeModules.CalendarModule;
CalendarModule.createCalendarEvent('Test Event', 'Office')
.then(eventId => {
console.log('Δημιουργήθηκε συμβάν με id:', eventId);
})
.catch(error => {
console.error('Απέτυχε:', error);
});
Στην native πλευρά iOS, το module εμφανίζεται ως κλάση Objective-C με τη μακροεντολή RCT_EXPORT_MODULE. Η μέθοδος εξάγεται με τη μακροεντολή RCT_EXPORT_METHOD και το React Native την εγγράφει αυτόματα στο Bridge. Τα ορίσματα μεταβιβάζονται ανά θέση και πρέπει να αντιστοιχούν στους υποστηριζόμενους τύπους JSON: NSString, NSNumber, NSArray, NSDictionary, BOOL.
// Εγγραφή iOS Native Module στο 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 έχει μια σειρά από θεμελιώδεις περιορισμούς απόδοσης. Ο κύριος από αυτούς είναι η υποχρεωτική ασύγχρονη λειτουργία και η σειριοποίηση. Κάθε κλήση native μεθόδου μετατρέπει τα δεδομένα σε συμβολοσειρά JSON, προσθέτοντας καθυστέρηση και καταναλώνοντας μνήμη. Για λειτουργίες με μεγάλο όγκο δεδομένων, όπως η επεξεργασία εικόνων ή η εργασία με βίντεο, αυτό γίνεται σημείο συμφόρησης.
Η σειριοποίηση και αποσειριοποίηση JSON απαιτούν χρόνο επεξεργαστή και μνήμη. Κάθε μήνυμα πρέπει να μετατραπεί σε συμβολοσειρά στην πλευρά JS, να μεταφερθεί μέσω της γέφυρας και να αναλυθεί στην native πλευρά. Σύμφωνα με δοκιμές της Callstack (2022), η σειριοποίηση ενός πίνακα 10.000 αριθμών μέσω Bridge διαρκεί περίπου 30–50 χιλιοστά του δευτερολέπτου, το οποίο είναι απαράδεκτο για κλήσεις υψηλής συχνότητας.
Το Bridge δεν είναι βελτιστοποιημένο για τη μεταφορά μεγάλων δυαδικών δεδομένων. Φωτογραφίες, αρχεία ήχου και ροές βίντεο απαιτούν εναλλακτικές προσεγγίσεις — για παράδειγμα, εγγραφή του αρχείου στον δίσκο και αποστολή της διαδρομής ως συμβολοσειρά. Αυτό δημιουργεί πρόσθετη επιβάρυνση για ανάγνωση και εγγραφή του συστήματος αρχείων.
Η επίγνωση αυτών των περιορισμών οδήγησε την ομάδα της Meta στην ανάπτυξη μιας νέας αρχιτεκτονικής React Native, στην οποία το Bridge αντικαθίσταται από JSI (JavaScript Interface) και Turbo Module. Το JSI επιτρέπει την άμεση κλήση native μεθόδων χωρίς σειριοποίηση, εξαλείφοντας το κύριο μειονέκτημα του Bridge.
Η σύγκριση του Bridge και του Turbo Module δείχνει θεμελιώδεις διαφορές στις αρχιτεκτονικές προσεγγίσεις. Το Bridge χρησιμοποιεί ασύγχρονη ουρά μηνυμάτων με σειριοποίηση JSON, ενώ το Turbo Module λειτουργεί μέσω JSI — μιας άμεσης διεπαφής μεταξύ JavaScript και C++ που επιτρέπει σύγχρονη κλήση native μεθόδων χωρίς μετατροπή δεδομένων.
| Χαρακτηριστικό | Bridge | Turbo Module |
|---|---|---|
| Τύπος κλήσης | Ασύγχρονος | Σύγχρονος και ασύγχρονος |
| Σειριοποίηση | JSON σε κάθε κλήση | Αντικείμενα JSI χωρίς αντιγραφή |
| Απόδοση | Μέτρια | Υψηλή |
| Τύπος δεδομένων | Δυναμικός | Στατικός (Codegen) |
| Φόρτωση | Όλα τα modules κατά την εκκίνηση | Αργή (κατά παραγγελία) |
Η επιλογή μεταξύ Bridge και Turbo Module εξαρτάται από την έκδοση του React Native. Για έργα σε React Native 0.72 και παλαιότερα, το Bridge παραμένει ο κύριος μηχανισμός. Από το React Native 0.73 και μετά, το Metro και η νέα αρχιτεκτονική υποστηρίζονται παράλληλα, επιτρέποντας σταδιακή μετεγκατάσταση. Η πλήρης μετάβαση στο Turbo Module απαιτεί αναβάθμιση σε React Native 0.76+ και ενεργοποίηση της νέας αρχιτεκτονικής στη διαμόρφωση.
Ας εξετάσουμε τον πλήρη κύκλο δημιουργίας και χρήσης ενός Native Module μέσω Bridge με το παράδειγμα ενός module για εργασία με ημερολόγιο. Το module θα δημιουργεί ένα συμβάν και θα επιστρέφει το αναγνωριστικό του. Αυτό το παράδειγμα καλύπτει τη ρύθμιση και για τις δύο πλατφόρμες — iOS και Android.
Στο Android, το Native Module δημιουργείται ως κλάση Java που κληρονομεί από ReactContextBaseJavaModule. Ο σχολιασμός @ReactMethod εξάγει τη μέθοδο στο Bridge. Για το Promise χρησιμοποιείται η διεπαφή Promise από το com.facebook.react.bridge.
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());
}
}
}
Το module εγγράφεται μέσω @ReactModule ή χειροκίνητα στο πακέτο της εφαρμογής. Το React Native το ανιχνεύει αυτόματα και το προσθέτει στο Bridge. Μετά την εγγραφή, το module είναι προσβάσιμο από την JavaScript μέσω του 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();
}
}
Είναι σημαντικό να σημειωθεί ότι το Bridge απαιτεί επανεκκίνηση της εφαρμογής κατά την προσθήκη νέων modules, καθώς ο χάρτης διαμόρφωσης χτίζεται μία φορά κατά την αρχικοποίηση. Αυτό το διαφοροποιεί από το Turbo Module, το οποίο φορτώνεται αργά και υποστηρίζει hot-reload modules χωρίς επανεκκίνηση.
Συχνές Ερωτήσεις
Το Bridge χρησιμοποιεί πάντα ασύγχρονη ουρά και σειριοποίηση JSON, ενώ η άμεση μεταφορά μέσω JSI λειτουργεί σύγχρονα και χωρίς αντιγραφή δεδομένων. Το Bridge δημιουργεί καθυστέρηση για σειριοποίηση, αλλά εξασφαλίζει απομόνωση νημάτων.
Όχι, το Bridge υποστηρίζει μόνο ασύγχρονες κλήσεις. Για σύγχρονη αλληλεπίδραση απαιτείται η νέα αρχιτεκτονική με JSI και Turbo Module. Αυτός είναι ένας από τους βασικούς περιορισμούς που επιλύθηκαν στο React Native 0.76+.
Το Bridge υποστηρίζει τύπους που σειριοποιούνται σε JSON: συμβολοσειρές, αριθμούς, λογικές τιμές, πίνακες, λεξικά (αντικείμενα). Δυαδικά δεδομένα, όπως εικόνες, πρέπει να μεταφέρονται μέσω του συστήματος αρχείων ή κωδικοποίησης base64.
Για μέτρηση, χρησιμοποιήστε τα React DevTools και τον προφιλοποιητή React Native. Η καρτέλα Performance δείχνει τον αριθμό μηνυμάτων στην ουρά Bridge και τις καθυστερήσεις. Επίσης, διατίθεται το πακέτο react-native-bridge-spy για παρακολούθηση κυκλοφορίας.
Η μετάβαση συνιστάται για έργα που απαιτούν υψηλή απόδοση ή κατά τη δημιουργία νέων εφαρμογών σε React Native 0.76+. Για υπάρχοντα έργα, η μετεγκατάσταση μπορεί να είναι σταδιακή — και οι δύο αρχιτεκτονικές λειτουργούν παράλληλα.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης