Turbo Module to ewolucja modułów natywnych React Native, zbudowana na JavaScript Interface (JSI). W przeciwieństwie do Bridge, Turbo Module działa synchronicznie i bez serializacji JSON, co zapewnia znaczący wzrost wydajności. Według Meta Engineering Blog, 2024, Turbo Module jest kluczowym komponentem nowej architektury i jest dostępny w React Native 0.76+.
Najważniejsze
Turbo Module to komponent nowej architektury React Native, który zastępuje klasyczny Bridge do komunikacji JavaScript z kodem natywnym. W przeciwieństwie do Bridge, gdzie każda wiadomość jest serializowana do JSON i przesyłana asynchronicznie, Turbo Module używa JSI — warstwy pośredniczącej, która pozwala JavaScript bezpośrednio wywoływać funkcje napisane w C++.
Architektura Turbo Module została zaprezentowana przez zespół Meta na React Conf 2021 jako część większej przebudowy React Native pod kryptonimem „The New Architecture”. Oprócz Turbo Module, nowa architektura obejmuje Fabric (nowy renderer), Codegen (generator kodu) i JSI (interfejs komunikacji). Razem te komponenty rozwiązują problemy wydajnościowe, które narastały w React Native od 2015 roku.
Turbo Module rozwiązuje trzy kluczowe problemy klasycznych Native Module: asynchroniczność (wszystkie wywołania przechodzą przez kolejkę), serializację (każde wywołanie wymaga konwersji JSON) i ładowanie (wszystkie moduły są inicjowane przy starcie aplikacji). Dzięki Turbo Module metody natywne są wywoływane synchronicznie, dane są przesyłane bez kopiowania, a moduły są ładowane na żądanie.
JSI (JavaScript Interface) to API w C++, które tworzy warstwę pośredniczącą między silnikiem JavaScript (Hermes lub JSC) a kodem natywnym. JSI dostarcza obiekty-hosty — obiekty C++, które wyglądają jak zwykłe obiekty i metody JavaScript. Kiedy JavaScript wywołuje metodę takiego obiektu, JSI bezpośrednio wykonuje odpowiedni kod C++ bez serializacji i bez przełączania wątków.
Kluczową różnicą między JSI a Bridge jest brak kopiowania danych. W Bridge każda wartość jest serializowana do JSON, przesyłana przez kolejkę i deserializowana. JSI przekazuje wskaźniki do danych w pamięci, co pozwala pracować z dużymi ilościami danych bez utraty wydajności. Według testów Meta, wywołania JSI są 5–10 razy szybsze niż analogiczne wywołania przez Bridge.
JSI definiuje interfejs HostObject — klasę C++, którą React Native rejestruje w środowisku JS jako zwykły obiekt. Gdy kod JS odwołuje się do właściwości lub wywołuje metodę HostObject, JSI przechwytuje wywołanie i wykonuje kod C++. Pozwala to na wykonywanie operacji synchronicznie, bez oczekiwania na kolejkę Bridge.
// Przykład JSI HostObject — synchroniczne wywołanie natywne
class ImageCompressorHostObject : public jsi::HostObject {
jsi::Value get(
jsi::Runtime& rt,
const jsi::PropNameID& propName
) override {
auto name = propName.utf8(rt);
if (name == "compressImage") {
return jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forUtf8(rt, name),
2,
[](jsi::Runtime& rt,
const jsi::Value& thisValue,
const jsi::Value* args,
size_t count) -> jsi::Value {
return jsi::Value(rt, compressNative(
args[0].asString(rt).utf8(rt),
args[1].asNumber()
));
}
);
}
return jsi::Value::undefined();
}
};
Powyższy kod pokazuje, jak JSI HostObject obsługuje wywołanie compressImage z JavaScript. Funkcja przyjmuje dwa argumenty (ścieżkę i jakość), wywołuje natywną funkcję compressNative i zwraca wynik — wszystko synchronicznie, bez Bridge, bez JSON. To kluczowa zaleta JSI w porównaniu z klasyczną architekturą.
JSI jest częścią głównego środowiska uruchomieniowego React Native i nie zależy od konkretnego silnika JavaScript. Działa zarówno z Hermes, jak i z JavaScriptCore (JSC), zapewniając jednolity interfejs do komunikacji ze środowiskiem natywnym.
Porównanie Turbo Module i Bridge pokazuje ewolucję architektury React Native. Bridge został zaprojektowany do szybkiego uruchomienia React Native w 2015 roku, ale wraz ze wzrostem złożoności aplikacji jego ograniczenia stały się krytyczne. Turbo Module rozwiązuje te problemy na poziomie architektury.
| Cecha | Bridge | Turbo Module |
|---|---|---|
| Szybkość wywołania | 5–15 ms narzutu | 0.1–0.5 ms narzutu |
| Synchroniczność | Tylko asynchronicznie | Synchronicznie i asynchronicznie |
| Serializacja | JSON przy każdym wywołaniu | Obiekty JSI bez kopiowania |
| Bezpieczeństwo typów | Nie | Codegen + TypeScript |
| Inicjalizacja | Wszystkie moduły przy starcie | Leniwie, na żądanie |
W praktyce różnica jest najbardziej zauważalna przy częstych wywołaniach metod natywnych — na przykład podczas przetwarzania multimediów lub pracy z GPU. Dla rzadkich wywołań (raz na sesję) różnica w wydajności jest nieznaczna. Turbo Module ułatwia również pracę z dużymi danymi binarnymi — obrazami, wideo, protokołami binarnymi — które w Bridge wymagały obejść z systemem plików.
Tworzenie Turbo Module rozpoczyna się od zdefiniowania specyfikacji w TypeScript. Codegen automatycznie generuje interfejsy C++ oraz stuby Objective-C/Java na podstawie tej specyfikacji. To całkowicie zmienia podejście do rozwoju — programista opisuje API raz, a Codegen tworzy resztę.
// ImageCompressor.ts — specyfikacja Turbo Module
import type { TurboModule } from 'react-native';
import type { Double } from 'react-native/Libraries/Types/CodegenTypes';
export interface Spec extends TurboModule {
compressImage(
imagePath: string,
quality: Double
): Promise<string>;
}
Codegen analizuje specyfikację TypeScript i generuje C++ HostObject, protokół Objective-C oraz interfejs Java. Programiście pozostaje jedynie zaimplementowanie logiki natywnej. Takie podejście gwarantuje, że typy po stronie JavaScript i natywnej zawsze są zgodne, eliminując błędy ręcznego mapowania.
// Implementacja TurboModule dla iOS (wygenerowany stub)
@interface ImageCompressorModule ()
RCT_EXPORT_MODULE(ImageCompressor)
@end
@implementation ImageCompressorModule
RCT_EXPORT_METHOD(compressImage:(NSString *)imagePath
quality:(NSNumber *)quality
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSData *compressed = [ImageProcessor compressAtPath:imagePath
quality:quality.doubleValue];
resolve([NSString stringWithUTF8String:compressed.UTF8String]);
}
@end
Ważną zaletą jest leniwe ładowanie. Turbo Module nie jest inicjowany przy uruchomieniu aplikacji, a tworzony dopiero przy pierwszym odwołaniu z JavaScript. Skraca to czas uruchomienia aplikacji o 30–50% w porównaniu z klasycznym podejściem, gdzie wszystkie Native Module są ładowane od razu.
Przejście z Bridge na Turbo Module nie wymaga całkowitego przepisywania aplikacji. React Native 0.73+ obsługuje obie architektury równolegle — moduły Bridge nadal działają, a nowe moduły można tworzyć jako Turbo Module. Pozwala to na stopniową migrację, moduł po module.
Aby włączyć nową architekturę w projekcie React Native 0.76+, ustaw flagę newArchEnabled na true w pliku react-native.config.js. Po tym wszystkie istniejące Native Module nadal działają przez Bridge, a nowe moduły mogą być tworzone jako Turbo Module. Codegen automatycznie obsługuje oba warianty.
// react-native.config.js — włącz nową architekturę
module.exports = {
project: {
ios: {},
android: {},
},
assets: [],
newArchEnabled: true,
};
Zaleca się rozpoczęcie migracji od modułów, które są najczęściej wywoływane z JavaScript — to one uzyskają największy wzrost wydajności. Moduły wywoływane rzadko (raz na sesję) można pozostawić na Bridge bez znaczącej utraty wydajności.
Często zadawane pytania
Nie, Turbo Module wymaga React Native 0.73+ z włączoną nową architekturą. Od wersji 0.76 nowa architektura stała się stabilna i zalecana do projektów produkcyjnych.
Tak, Turbo Module obsługuje obie platformy. JSI jest wieloplatformową warstwą C++, a Codegen generuje stuby Objective-C i Java odpowiednio dla iOS i Android.
Nie, Turbo Module działa z każdym silnikiem JS przez JSI. Jednak Hermes jest zalecany, ponieważ jest zoptymalizowany do pracy z JSI i nową architekturą React Native.
Debugowanie Turbo Module odbywa się przez Xcode lub Android Studio jak zwykłego kodu natywnego. Dodatkowo dostępny jest Flipper do śledzenia wywołań JSI i wydajności modułów.
Turbo Module praktycznie nie wpływa na rozmiar aplikacji. Kod C++ JSI jest już częścią React Native, a generowany kod jest minimalny — tylko interfejsy bez duplikowania logiki.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również