Bridge là một thành phần kiến trúc của React Native cung cấp giao tiếp bất đồng bộ giữa luồng JavaScript và môi trường native của iOS và Android. Nó truyền các thông điệp JSON được tuần tự hóa qua hàng đợi, cho phép gọi các API native từ mã JS. Theo Meta, 2024, Bridge vẫn là nền tảng của các ứng dụng hiện có, mặc dù nó thua kém về hiệu suất so với kiến trúc mới trên JSI.
Điểm chính
Bridge là một yếu tố kiến trúc quan trọng của React Native cung cấp giao tiếp bất đồng bộ hai chiều giữa luồng JavaScript, nơi logic nghiệp vụ của ứng dụng được thực thi, và các luồng native iOS và Android. Kể từ khi React Native ra mắt vào năm 2015, Bridge là cách duy nhất để mã JS tương tác với các API nền tảng — máy ảnh, định vị, hệ thống tệp, thông báo và các khả năng native khác.
Kiến trúc Bridge dựa trên nguyên lý hàng đợi thông điệp (message queue). Khi mã JavaScript gọi một phương thức native, yêu cầu được tuần tự hóa thành chuỗi JSON, được đặt vào hàng đợi và gửi bất đồng bộ sang phía native. Mã native xử lý yêu cầu, thực hiện thao tác tương ứng và gửi kết quả trở lại qua cùng hàng đợi đến luồng JS. Theo báo cáo của Meta tại React Conf 2021, có đến 10.000 thông điệp mỗi giây đi qua Bridge trong một ứng dụng trung bình.
Các luồng chính tham gia vào hoạt động của Bridge: JavaScript Thread (thực thi mã JS), Native Thread (thực thi thao tác native) và Shadow Thread (tính toán bố cục bằng Yoga). Mỗi luồng hoạt động độc lập, đảm bảo tính phản hồi của UI — các hoạt ảnh native không bị chặn bởi các tính toán JS.
Bridge sử dụng ba cơ chế chính để giao tiếp: MessageQueue, tuần tự hóa JSON và gộp thông điệp (batching). MessageQueue là một thành phần nội bộ của React Native quản lý hàng đợi cuộc gọi giữa JS và phía native. Mỗi lời gọi phương thức native được đặt vào hàng đợi, tuần tự hóa và gửi theo lô để tối ưu hóa hiệu suất.
MessageQueue hoạt động theo nguyên lý gộp lô: các lời gọi phương thức native tích lũy và được gửi dưới dạng một nhóm duy nhất (lô) cứ sau 5–15 mili giây. Điều này làm giảm chi phí tuần tự hóa vì nhiều lời gọi được đóng gói trong một gói JSON duy nhất. Ở phía native, các thông điệp được giải tuần tự hóa và phân phối đến các mô-đun tương ứng.
Các mô-đun native được đăng ký tự động qua macro hoặc chú thích. iOS sử dụng macro RCT_EXPORT_MODULE, Android sử dụng chú thích @ReactMethod. React Native quét các mô-đun đã đăng ký khi khởi động ứng dụng và xây dựng một bản đồ JSON cấu hình của tất cả các phương thức có sẵn. Bản đồ này được truyền đến môi trường JS, và JavaScript biết được phương thức nào có thể được gọi.
Dữ liệu đi theo đường dẫn sau: JavaScript gọi NativeModules.CalendarModule.createCalendarEvent(). Phương thức được tuần tự hóa thành một thông điệp JSON với định danh mô-đun, tên phương thức và đối số. Thông điệp đi vào MessageQueue. Trên luồng native, thông điệp được giải tuần tự hóa và chuyền đến mô-đun tương ứng. Kết quả thực thi được tuần tự hóa trở lại và gửi đến luồng JS dưới dạng Promise hoặc callback.
// Native module call from JavaScript via Bridge
import { NativeModules } from 'react-native';
const CalendarModule = NativeModules.CalendarModule;
CalendarModule.createCalendarEvent('Test Event', 'Office')
.then(eventId => {
console.log('Created event with id:', eventId);
})
.catch(error => {
console.error('Failed:', error);
});
Ở phía native iOS, mô-đun trông giống một lớp Objective-C với macro RCT_EXPORT_MODULE. Phương thức được xuất bằng macro RCT_EXPORT_METHOD, và React Native tự động đăng ký nó trong Bridge. Các đối số được truyền theo vị trí và phải tương ứng với các kiểu JSON được hỗ trợ: NSString, NSNumber, NSArray, NSDictionary, BOOL.
// iOS Native Module registration 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 có một số hạn chế hiệu suất cơ bản. Chính là tính bất đồng bộ và tuần tự hóa bắt buộc. Mỗi lời gọi phương thức native chuyển đổi dữ liệu thành chuỗi JSON, làm tăng độ trễ và tiêu tốn bộ nhớ. Đối với các thao tác với khối lượng dữ liệu lớn, như xử lý hình ảnh hoặc làm việc với video, điều này trở thành nút cổ chai.
Việc tuần tự hóa và giải tuần tự hóa JSON tiêu tốn thời gian CPU và bộ nhớ. Mỗi thông điệp phải được chuyển đổi thành chuỗi ở phía JS, truyền qua cầu nối và phân tích ở phía native. Theo các thử nghiệm của Callstack (2022), việc tuần tự hóa một mảng 10.000 số qua Bridge mất khoảng 30–50 mili giây, điều không thể chấp nhận được đối với các cuộc gọi tần số cao.
Bridge không được tối ưu hóa để truyền dữ liệu nhị phân lớn. Ảnh, tệp âm thanh và luồng video yêu cầu các cách tiếp cận thay thế — ví dụ, ghi tệp vào đĩa và truyền đường dẫn dưới dạng chuỗi. Điều này tạo ra chi phí bổ sung cho các thao tác đọc và ghi hệ thống tệp.
Nhận thức về những hạn chế này đã dẫn đến việc nhóm Meta phát triển một kiến trúc React Native mới, trong đó Bridge được thay thế bằng JSI (JavaScript Interface) và Turbo Module. JSI cho phép gọi các phương thức native trực tiếp, không cần tuần tự hóa, loại bỏ nhược điểm chính của Bridge.
So sánh Bridge và Turbo Module cho thấy sự khác biệt cơ bản trong cách tiếp cận kiến trúc. Bridge sử dụng hàng đợi thông điệp bất đồng bộ với tuần tự hóa JSON, trong khi Turbo Module hoạt động qua JSI — một giao diện trực tiếp giữa JavaScript và C++ cho phép gọi các phương thức native một cách đồng bộ mà không cần chuyển đổi dữ liệu.
| Đặc điểm | Bridge | Turbo Module |
|---|---|---|
| Loại cuộc gọi | Bất đồng bộ | Đồng bộ và bất đồng bộ |
| Tuần tự hóa | JSON ở mỗi cuộc gọi | Đối tượng JSI không sao chép |
| Hiệu suất | Trung bình | Cao |
| Kiểu | Động | Tĩnh (Codegen) |
| Tải | Tất cả mô-đun khi khởi động | Chậm (theo yêu cầu) |
Việc lựa chọn giữa Bridge và Turbo Module phụ thuộc vào phiên bản React Native. Đối với các dự án trên React Native 0.72 trở về trước, Bridge vẫn là cơ chế chính. Bắt đầu từ React Native 0.73, Metro và kiến trúc mới được hỗ trợ song song, cho phép di chuyển dần dần. Việc chuyển đổi hoàn toàn sang Turbo Module yêu cầu nâng cấp lên React Native 0.76+ và kích hoạt kiến trúc mới trong cấu hình.
Hãy xem xét toàn bộ chu trình tạo và sử dụng Native Module qua Bridge với ví dụ mô-đun lịch. Mô-đun sẽ tạo một sự kiện và trả về định danh của nó. Ví dụ này bao gồm cài đặt cho cả hai nền tảng — iOS và Android.
Trên Android, Native Module được tạo dưới dạng một lớp Java kế thừa ReactContextBaseJavaModule. Chú thích @ReactMethod xuất phương thức ra Bridge. Đối với Promise, giao diện Promise từ com.facebook.react.bridge được sử dụng.
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());
}
}
}
Mô-đun được đăng ký qua @ReactModule hoặc thủ công trong gói ứng dụng. React Native tự động phát hiện và thêm nó vào Bridge. Sau khi đăng ký, mô-đun có thể truy cập từ JavaScript qua 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();
}
}
Điều quan trọng cần lưu ý là Bridge yêu cầu khởi động lại ứng dụng khi thêm mô-đun mới, vì bản đồ cấu hình được xây dựng một lần trong quá trình khởi tạo. Điều này phân biệt nó với Turbo Module, module này tải chậm và hỗ trợ tải lại nóng mô-đun mà không cần khởi động lại.
Câu hỏi thường gặp
Bridge luôn sử dụng hàng đợi bất đồng bộ và tuần tự hóa JSON, trong khi truyền trực tiếp qua JSI hoạt động đồng bộ và không sao chép dữ liệu. Bridge tạo độ trễ tuần tự hóa nhưng đảm bảo cách ly luồng.
Không, Bridge chỉ hỗ trợ các cuộc gọi bất đồng bộ. Tương tác đồng bộ yêu cầu kiến trúc mới với JSI và Turbo Module. Đây là một trong những hạn chế chính đã được giải quyết trong React Native 0.76+.
Bridge hỗ trợ các kiểu có thể tuần tự hóa thành JSON: chuỗi, số, giá trị boolean, mảng, từ điển (đối tượng). Dữ liệu nhị phân như hình ảnh phải được truyền qua hệ thống tệp hoặc mã hóa base64.
Để đo lường, hãy sử dụng React DevTools và trình phân tích React Native. Tab Performance hiển thị số lượng thông điệp trong hàng đợi Bridge và độ trễ. Gói react-native-bridge-spy cũng có sẵn để giám sát lưu lượng truy cập.
Nên chuyển đối với các dự án đòi hỏi hiệu suất cao hoặc khi tạo ứng dụng mới trên React Native 0.76+. Đối với các dự án hiện có, việc di chuyển có thể dần dần — cả hai kiến trúc đều hoạt động song song.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm