Bridge — یک جزء معماری React Native است که ارتباط ناهمزمان بین رشته JavaScript و محیط بومی iOS و Android را فراهم میکند. این مؤلفه پیامهای سریالشده JSON را از طریق صف ارسال میکند و امکان فراخوانی APIهای بومی از کد JS را فراهم میکند. به گزارش Meta، 2024، Bridge همچنان اساس برنامههای موجود باقی میماند، هرچند از نظر عملکرد نسبت به معماری جدید مبتنی بر JSI پایینتر است.
نکات اصلی
Bridge (پل) — یک عنصر کلیدی معماری React Native است که ارتباط دوطرفه ناهمزمان بین رشته JavaScript، که منطق تجاری برنامه در آن اجرا میشود، و رشتههای بومی iOS و Android را فراهم میکند. از زمان انتشار React Native در سال 2015، Bridge تنها راه تعامل کد JS با APIهای پلتفرمی — دوربین، موقعیتیابی جغرافیایی، سیستم فایل، اعلانها و سایر قابلیتهای بومی باقی مانده است.
معماری Bridge بر اساس اصل صف پیام (message queue) استوار است. وقتی کد JavaScript یک متد بومی را فراخوانی میکند، درخواست به یک رشته JSON سریالسازی میشود، در صف قرار میگیرد و به طور ناهمزمان به سمت بومی ارسال میشود. کد بومی درخواست را پردازش میکند، عملیات مربوطه را انجام میدهد و نتیجه را از طریق همان صف به رشته JS برمیگرداند. طبق گزارش Meta در React Conf 2021، در یک برنامه معمولی تا 10000 پیام در ثانیه از Bridge عبور میکند.
رشتههای اصلی شرکتکننده در کار Bridge: JavaScript Thread (اجرای کد JS)، Native Thread (اجرای عملیات بومی) و Shadow Thread (محاسبه طرح با استفاده از Yoga). هر رشته به طور مستقل کار میکند که پاسخگویی رابط کاربری را تضمین میکند — انیمیشنهای بومی توسط محاسبات JS مسدود نمیشوند.
Bridge از سه مکانیسم کلیدی برای ارتباط استفاده میکند: MessageQueue، سریالسازی JSON و دستهبندی پیامها. MessageQueue یک جزء داخلی React Native است که صف فراخوانیها بین JS و سمت بومی را مدیریت میکند. هر فراخوانی متد بومی در صف قرار میگیرد، سریالسازی میشود و برای بهینهسازی عملکرد به صورت دستهای ارسال میشود.
MessageQueue بر اساس اصل دستهبندی کار میکند: فراخوانیهای متدهای بومی جمع میشوند و هر 5 تا 15 میلیثانیه به صورت یک گروه (batch) ارسال میشوند. این کار سربار سریالسازی را کاهش میدهد، زیرا چندین فراخوانی در یک بسته JSON بستهبندی میشوند. در سمت بومی، پیامها از سریال خارج شده و به ماژولهای مربوطه توزیع میشوند.
ماژولهای بومی به طور خودکار از طریق ماکروها یا حاشیهنویسیها ثبت میشوند. در iOS از ماکرو RCT_EXPORT_MODULE و در Android از حاشیهنویسی @ReactMethod استفاده میشود. React Native هنگام راهاندازی برنامه، ماژولهای ثبت شده را اسکن میکند و یک نقشه JSON پیکربندی از تمام متدهای موجود میسازد. این نقشه به محیط JS منتقل میشود و JavaScript متوجه میشود که چه متدهایی قابل فراخوانی هستند.
دادهها مسیر زیر را طی میکنند: JavaScript NativeModules.CalendarModule.createCalendarEvent() را فراخوانی میکند. متد به یک پیام JSON با شناسه ماژول، نام متد و آرگومانها سریالسازی میشود. پیام وارد صف MessageQueue میشود. در رشته بومی، پیام از سریال خارج شده و به ماژول مربوطه منتقل میشود. نتیجه اجرا دوباره سریالسازی شده و به عنوان Promise یا callback به رشته JS ارسال میشود.
// فراخوانی ماژول بومی از JavaScript از طریق Bridge
import { NativeModules } from 'react-native';
const CalendarModule = NativeModules.CalendarModule;
CalendarModule.createCalendarEvent('Test Event', 'Office')
.then(eventId => {
console.log('رویداد با شناسه ایجاد شد:', eventId);
})
.catch(error => {
console.error('ناموفق:', error);
});
در سمت بومی iOS، ماژول به صورت یک کلاس Objective-C با ماکرو RCT_EXPORT_MODULE ظاهر میشود. متد با ماکرو RCT_EXPORT_METHOD صادر میشود و React Native آن را به طور خودکار در Bridge ثبت میکند. آرگومانها بر اساس موقعیت منتقل میشوند و باید با انواع JSON پشتیبانی شده مطابقت داشته باشند: NSString، NSNumber، NSArray، NSDictionary، BOOL.
// ثبت ماژول بومی iOS در 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 دارای تعدادی محدودیت عملکردی اساسی است. مهمترین آنها ناهمزمانی اجباری و سریالسازی است. هر فراخوانی متد بومی دادهها را به رشته JSON تبدیل میکند که تأخیر ایجاد میکند و حافظه مصرف میکند. برای عملیات با حجم داده بزرگ، مانند پردازش تصویر یا کار با ویدیو، این به یک گلوگاه تبدیل میشود.
سریالسازی و از سریال خارج کردن JSON زمان پردازنده و حافظه مصرف میکند. هر پیام باید در سمت JS به رشته تبدیل شود، از طریق پل منتقل شود و در سمت بومی تجزیه شود. طبق آزمایشهای Callstack (2022)، سریالسازی یک آرایه 10000 عددی از طریق Bridge حدود 30 تا 50 میلیثانیه طول میکشد که برای فراخوانیهای با فرکانس بالا غیرقابل قبول است.
Bridge برای انتقال دادههای باینری بزرگ بهینه نشده است. عکسها، فایلهای صوتی و جریانهای ویدیویی نیاز به رویکردهای جایگزین دارند — مثلاً نوشتن فایل روی دیسک و ارسال مسیر به صورت رشته. این سربار اضافی برای خواندن و نوشتن سیستم فایل ایجاد میکند.
آگاهی از این محدودیتها تیم Meta را به توسعه معماری جدید React Native سوق داد که در آن Bridge با JSI (JavaScript Interface) و Turbo Module جایگزین میشود. JSI امکان فراخوانی مستقیم متدهای بومی بدون سریالسازی را فراهم میکند که نقص اصلی Bridge را برطرف میکند.
مقایسه Bridge و Turbo Module تفاوتهای اساسی در رویکردهای معماری را نشان میدهد. Bridge از صف پیام ناهمزمان با سریالسازی JSON استفاده میکند، در حالی که Turbo Module از طریق JSI — یک رابط مستقیم بین JavaScript و C++ کار میکند که امکان فراخوانی همزمان متدهای بومی بدون تبدیل داده را فراهم میکند.
| ویژگی | Bridge | Turbo Module |
|---|---|---|
| نوع فراخوانی | ناهمزمان | همزمان و ناهمزمان |
| سریالسازی | JSON در هر فراخوانی | اشیاء JSI بدون کپی |
| عملکرد | متوسط | بالا |
| تایپبندی | پویا | ایستا (Codegen) |
| بارگذاری | همه ماژولها در شروع | تنبل (بر اساس تقاضا) |
انتخاب بین Bridge و Turbo Module به نسخه React Native بستگی دارد. برای پروژههای React Native 0.72 و بالاتر، Bridge مکانیسم اصلی باقی میماند. از React Native 0.73 به بعد، Metro و معماری جدید به صورت موازی پشتیبانی میشوند و امکان مهاجرت تدریجی را فراهم میکنند. انتقال کامل به Turbo Module نیاز به بهروزرسانی به React Native 0.76+ و فعالسازی معماری جدید در پیکربندی دارد.
بیایید چرخه کامل ایجاد و استفاده از Native Module را از طریق Bridge با مثال ماژول کار با تقویم بررسی کنیم. ماژول یک رویداد ایجاد میکند و شناسه آن را برمیگرداند. این مثال راهاندازی برای هر دو پلتفرم 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());
}
}
}
ماژول از طریق @ReactModule یا به صورت دستی در بسته برنامه ثبت میشود. React Native به طور خودکار آن را شناسایی کرده و به Bridge اضافه میکند. پس از ثبت، ماژول از 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 هنگام افزودن ماژولهای جدید نیاز به راهاندازی مجدد برنامه دارد، زیرا نقشه پیکربندی یک بار در هنگام مقداردهی اولیه ساخته میشود. این آن را از Turbo Module متمایز میکند که به صورت تنبل بارگذاری میشود و از بارگذاری داغ ماژولها بدون راهاندازی مجدد پشتیبانی میکند.
سوالات متداول
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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید