Bridge คือส่วนประกอบทางสถาปัตยกรรมของ React Native ที่ให้การสื่อสารแบบอะซิงโครนัสระหว่างเธรด JavaScript และสภาพแวดล้อม native ของ iOS และ Android โดยส่งข้อความ JSON ที่ถูกซีเรียลไลซ์ผ่านคิว ทำให้สามารถเรียก API native จากโค้ด 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) แต่ละเธรดทำงานอย่างอิสระ ทำให้มั่นใจในความตอบสนองของ UI — แอนิเมชัน native ไม่ถูกบล็อกโดยการคำนวณ JS
Bridge ใช้กลไกหลักสามอย่างสำหรับการสื่อสาร: MessageQueue, การซีเรียลไลซ์ JSON และการรวมข้อความ (batching) MessageQueue คือส่วนประกอบภายในของ React Native ที่จัดการคิวการเรียกระหว่าง JS และฝั่ง native การเรียกเมธอด native แต่ละครั้งจะถูกวางในคิว ซีเรียลไลซ์ และส่งเป็นชุดเพื่อเพิ่มประสิทธิภาพ
MessageQueue ทำงานบนหลักการของ การรวมเป็นชุด: การเรียกเมธอด native จะสะสมและถูกส่งเป็นกลุ่มเดียว (ชุด) ทุกๆ 5–15 มิลลิวินาที ซึ่งช่วยลดค่าใช้จ่ายในการซีเรียลไลซ์ เนื่องจากการเรียกหลายครั้งถูกบรรจุในแพ็คเกจ JSON เดียวกัน ฝั่ง native ข้อความจะถูกดีซีเรียลไลซ์และกระจายไปยังโมดูลที่เกี่ยวข้อง
โมดูล native ถูกลงทะเบียนโดยอัตโนมัติผ่านมาโครหรือคำอธิบายประกอบ iOS ใช้มาโคร RCT_EXPORT_MODULE, Android ใช้คำอธิบายประกอบ @ReactMethod React Native จะสแกนโมดูลที่ลงทะเบียนเมื่อเริ่มต้นแอปพลิเคชันและสร้างแผนที่ JSON การกำหนดค่าของเมธอดทั้งหมดที่มีอยู่ แผนที่นี้ถูกส่งไปยังสภาพแวดล้อม JS และ JavaScript จะรู้ว่าเมธอดใดบ้างที่สามารถเรียกได้
ข้อมูลเป็นไปตามเส้นทางนี้: JavaScript เรียก NativeModules.CalendarModule.createCalendarEvent() เมธอดถูกซีเรียลไลซ์เป็นข้อความ JSON พร้อมด้วยตัวระบุโมดูล ชื่อเมธอด และอาร์กิวเมนต์ ข้อความเข้าสู่ MessageQueue บนเธรด native ข้อความถูกดีซีเรียลไลซ์และส่งไปยังโมดูลที่เกี่ยวข้อง ผลลัพธ์การดำเนินการถูกซีเรียลไลซ์กลับและส่งไปยังเธรด JS เป็น Promise หรือ callback
// การเรียกโมดูล native จาก 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 โมดูลจะปรากฏเป็นคลาส Objective-C ที่มีมาโคร RCT_EXPORT_MODULE เมธอดถูกส่งออกโดยใช้มาโคร RCT_EXPORT_METHOD และ React Native จะลงทะเบียนใน Bridge โดยอัตโนมัติ อาร์กิวเมนต์ถูกส่งตามตำแหน่งและต้องสอดคล้องกับประเภท JSON ที่รองรับ: NSString, NSNumber, NSArray, NSDictionary, BOOL
// การลงทะเบียนโมดูล native 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 มีข้อจำกัดด้านประสิทธิภาพพื้นฐานหลายประการ หลักๆ คือความอะซิงโครนัสและการซีเรียลไลซ์ที่บังคับ การเรียกเมธอด native แต่ละครั้งจะแปลงข้อมูลเป็นสตริง JSON ซึ่งเพิ่มความหน่วงและใช้หน่วยความจำ สำหรับการดำเนินการที่มีปริมาณข้อมูลมาก เช่น การประมวลผลภาพหรือการทำงานกับวิดีโอ สิ่งนี้กลายเป็นคอขวด
การซีเรียลไลซ์และดีซีเรียลไลซ์ JSON ใช้เวลา CPU และหน่วยความจำ ข้อความแต่ละข้อความต้องถูกแปลงเป็นสตริงฝั่ง 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) |
| การโหลด | โมดูลทั้งหมดเมื่อเริ่มต้น | ขี้เกียจ (ตามต้องการ) |
การเลือกระหว่าง 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 สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม