JSI (JavaScript Interface) — este un strat software în React Native care oferă acces sincron direct din JavaScript la obiecte și funcții C++, înlocuind podul asincron JSON — Bridge. Spre deosebire de predecesor, JSI permite apelarea metodelor native fără serializarea mesajelor și transmiterea referințelor la obiecte C++ direct în mediul JS. Conform datelor React Native Team (2025), JSI asigură o accelerare de până la 10 ori a interacțiunii JS cu codul nativ în scenarii cu schimb intensiv de date.
Principalele
JSI (JavaScript Interface) — este un strat C++ care oferă motorului JavaScript (Hermes, JavaScriptCore, V8) posibilitatea de a accesa direct obiecte, funcții și memorie C++. Spre deosebire de Bridge, care serializa apelurile în JSON și le transmitea printr-o coadă asincronă, JSI permite codului JS să apeleze sincron metode C++ și să primească rezultatul imediat.
JSI a fost introdusă în React Native 0.64 ca parte a noii arhitecturi (New Architecture). Scopul principal a fost eliminarea blocajului reprezentat de Bridge: fiecare interacțiune între JS și codul nativ consuma timp pentru serializare, deserializare și transmitere prin coada de mesaje. JSI rezolvă această problemă oferind motorului JS acces direct la obiecte C++ prin îmbrăcăminți care implementează interfața jsi::Value, jsi::Object și jsi::Function.
JSI nu este un înlocuitor „unu la unu” pentru Bridge — este o abordare fundamental diferită a integrării. Bridge funcționa ca o cutie poștală: JS trimitea un mesaj, acesta trecea prin coadă, partea nativă îl procesa și trimitea un răspuns. JSI funcționează ca un pointer: JS primește o referință la un obiect C++ și poate apela metodele sale sincron, ca pe funcții JS obișnuite. Aceasta este diferența fundamentală în arhitectura interacțiunii celor două medii.
Necesitatea JSI a apărut din cauza limitărilor Bridge-ului original, creat în React Native 2015. Odată cu creșterea popularității framework-ului și complexificarea aplicațiilor, problema performanței a devenit evidentă: fiecare apel al unui modul nativ necesita cel puțin 3–5 ms pentru serializare. Pentru operații simple, precum citirea valorii unui senzor sau obținerea dimensiunii ecranului, era acceptabil, dar pentru animații, lucrul cu grafica și procesarea fluxurilor de date — critic. Echipa React Native a început lucrul la noua arhitectură în 2019, iar JSI a devenit fundamentul acesteia.
JSI este proiectată ca o abstracție peste motoarele JavaScript. Oferă un API C++ unitar care este implementat pentru fiecare motor specific: Hermes, JavaScriptCore (iOS), V8 (Android). Aceasta înseamnă că dezvoltatorul nu trebuie să-și facă griji în privința diferențelor dintre motoare — Fabric și TurboModules funcționează la fel indiferent de motorul JS utilizat.
La baza JSI stă conceptul de Host Objects — obiecte C++ care sunt exportate în mediul JS ca obiecte JS native. Când codul JS accesează o proprietate sau o metodă a unui astfel de obiect, JSI interceptează apelul și îl delegă metodei C++ corespunzătoare. Acest lucru se întâmplă sincron, în același fir, fără comutare de context și fără alocare de memorie pentru un șir JSON.
Fiecare Host Object implementează interfața jsi::HostObject cu metodele get, set și getPropertyNames. Motorul JS apelează aceste metode la fiecare accesare a proprietăților obiectului. De exemplu, la apelul NativeModule.someMethod() în JS, JSI transformă acest apel într-un apel C++ al metodei corespunzătoare a Host Object. Valoarea returnată este transmisă înapoi în JS ca jsi::Value — un tip generalizat care poate reprezenta un număr, un șir, o valoare booleană, un obiect sau undefined.
O caracteristică importantă a JSI este absența cozii de mesaje. Bridge folosea o coadă asincronă: JS trimitea o cerere, trecea la alte sarcini, partea nativă procesa cererea, iar rezultatul revenea printr-un callback. JSI funcționează sincron: dacă JS apelează o metodă a unui modul nativ prin JSI, execuția codului JS este suspendată până la obținerea rezultatului. Aceasta simplifică logica (nu este nevoie să așteptați callback-uri) și elimină race conditions, dar necesită prudență — apelurile sincrone lungi blochează firul JS.
Valorile create prin JSI trăiesc în mediul de execuție al motorului JS și sunt gestionate de colectorul de gunoi. Când codul C++ creează un jsi::String sau jsi::Object și îl returnează în JS, mediul gestionează automat memoria. Dacă codul C++ dorește să păstreze o referință la o valoare JS între apeluri, utilizează jsi::Value::getWeak() sau jsi::Object::setProperty global cu păstrarea referinței pe obiectul rădăcină al runtime-ului. Aceasta previne ștergerea prematură de către colectorul de gunoi.
JSI nu este implicit sigură din punctul de vedere al firelor de execuție. Toate apelurile metodelor JSI trebuie să provină din firul în care este executat JS (de obicei, acesta este firul JS al React Native). Dacă un modul nativ lansează o activitate de fundal într-un fir separat, rezultatul trebuie transmis înapoi prin firul JS cu ajutorul apelului runOnJS din TurboModules. Această limitare este prețul pentru sincronicitate și absența serializării.
Diferența dintre JSI și Bridge are un caracter fundamental și afectează toate aspectele interacțiunii JS cu codul nativ. Bridge era asincron, serializa datele în JSON și folosea o coadă de mesaje; JSI este sincronă, lucrează cu referințe native și nu necesită serializare.
| Parametru | Bridge | JSI |
|---|---|---|
| Model de apel | Coadă asincronă | Apel direct sincron |
| Serializare | JSON (serializare + deserializare) | Nu (referințe directe la obiecte C++) |
| Întârziere | 3–10 ms per apel | 0.1–0.5 ms per apel |
| Tipizare | Dinamică (prin JSON) | Statică (prin Codegen) |
| Integrare C++ | Doar prin module native (Java/ObjC) | Directă, fără intermediari |
| Fir | Fir nativ separat | Fir JS (sincron) |
Conform datelor React Native Team, migrarea de la Bridge la JSI în aplicația Facebook Marketplace a redus timpul de pornire cu 35% și a diminuat consumul de memorie cu 20% datorită eliminării duplicării datelor între JS și partea nativă.
Bridge nu a fost o „greșeală” — a fost o decizie arhitecturală justificată la momentul creării React Native în 2015. Dezvoltarea nativă pentru două platforme cu limbi diferite necesita un format universal de schimb. JSON ca format de serializare era disponibil pe toate platformele și permitea unificarea interacțiunii. Problema s-a manifestat mai târziu, când React Native a început să fie utilizat pentru aplicații complexe cu mii de apeluri ale modulelor native pe secundă.
React Native păstrează compatibilitatea inversă: modulele native scrise pentru Bridge continuă să funcționeze în noua arhitectură printr-un strat de compatibilitate. Cu toate acestea, pentru modulele noi se recomandă utilizarea imediată a JSI prin TurboModules. Migrarea modulelor existente constă în înlocuirea protocolului de interacțiune fără modificarea logicii de business a modulului în sine.
JSI este stratul fundamental pe care sunt construite toate componentele noii arhitecturi React Native. Fără JSI, nici Fabric (noul renderer), nici TurboModules (module native optimizate) nu ar putea funcționa. JSI asigură un mod unitar de interacțiune a JS cu C++ la toate nivelurile.
Fabric — noul renderer React Native care utilizează JSI pentru acces sincron la reprezentările UI în C++. În arhitectura veche, randarea trecea prin Bridge: JS crea elemente React, le serializa în JSON, le trimitea prin Bridge, partea nativă le deserializa și crea UI. Fabric prin JSI creează obiecte C++ Shadow Tree direct din JS, calculează sincron Layout prin Yoga și transmite cadrele gata făcute rendererului nativ — fără nicio serializare.
TurboModules — reprezintă evoluția modulelor native React Native. În loc să înregistreze modulul în Bridge și să-i apeleze metodele prin JSON, TurboModules utilizează JSI pentru încărcare leneșă și apel direct. Când codul JS accesează pentru prima dată un modul, JSI creează un Host Object — acesta încarcă modulul nativ și oferă metodele sale ca funcții C++. Încărcarea leneșă înseamnă că modulul nu consumă memorie până la prima utilizare — acest lucru este deosebit de important în aplicațiile cu zeci de module native, multe dintre ele fiind utilizate doar pe anumite ecrane.
Pentru lucrul cu JSI în noua arhitectură se utilizează Codegen — un instrument care generează îmbrăcăminți C++ din specificații JavaScript. Dezvoltatorul descrie interfața modulului nativ în TypeScript sau Flow, iar Codegen generează cod C++ care implementează un Host Object compatibil JSI. Aceasta automatizează munca de rutină și garantează că tipurile de pe partea JS și C++ sunt sincronizate.
Să analizăm cum arată lucrul cu JSI în practică. În acest exemplu se creează o clasă C++ simplă care este exportată în JS prin JSI, iar metoda sa este apelată din codul JavaScript React Native.
// Calculator.h — antetul clasei C++ accesibil din JS
class Calculator {
public:
double add(double a, double b) { return a + b; }
double multiply(double a, double b) { return a * b; }
};
Clasa Calculator conține două metode aritmetice. Trebuie să o facem accesibilă din JS. În acest scop, creăm un Host Object care îmbrăcă Calculator și oferă metodele sale prin JSI.
// CalculatorHostObject.cpp — implementarea îmbrăcăminții JSI
class CalculatorHostObject : public jsi::HostObject {
private:
Calculator calc;
public:
jsi::Value get(jsi::Runtime& runtime,
const jsi::PropNameID& name) override {
auto propName = name.utf8(runtime);
if (propName == "add") {
return jsi::Function::createFromHostFunction(
runtime, name, 2,
[this](jsi::Runtime& runtime,
const jsi::Value& thisVal,
const jsi::Value* args,
size_t count) -> jsi::Value {
return jsi::Value(calc.add(
args[0].asNumber(),
args[1].asNumber()));
});
}
return jsi::Value::undefined();
}
};
În acest cod, metoda get este apelată de fiecare dată când JS accesează o proprietate a obiectului. Dacă numele proprietății este „adăugare”, se returnează o funcție C++ care primește două argumente din JS și apelează calc.add(). Valoarea este returnată ca jsi::Value — JSI convertește automat double într-un număr JS.
După înregistrarea Host Object în mediul JS, apelul arată ca o funcție JS obișnuită. Toate tipurile sunt verificate în faza de codogenerare, ceea ce elimină erorile de nepotrivire a tipurilor în timpul execuției.
// JavaScript — apelarea calculatorului C++ prin JSI
import { Calculator } from 'react-native-calculator'
const result = Calculator.add(5, 3)
console.log(result) // 8 — sincron, fără întârziere
const product = Calculator.multiply(4, 2.5)
console.log(product) // 10 — rezultat imediat
Observați: rezultatul este returnat imediat, fără Promise, fără await, fără callback-uri. Acesta este un apel sincron, care era imposibil în arhitectura Bridge. Pentru operații de lungă durată (citire fișier, cerere de rețea) trebuie utilizate modele asincrone — JSI nu elimină necesitatea firelor de fundal pentru sarcini grele.
În practică, majoritatea dezvoltatorilor nu scriu manual JSI Host Objects — această muncă este efectuată de Codegen, care generează îmbrăcăminți C++ pe baza specificațiilor TypeScript. Cu toate acestea, înțelegerea modului în care funcționează JSI sub capotă este necesară pentru depanarea eficientă a performanței și la crearea modulelor native complexe care necesită acces direct la bibliotecile C++ (Skia, FFmpeg, OpenCV).
Întrebări frecvente
Bridge funcționează asincron prin serializare JSON și o coadă de mesaje — fiecare apel necesită 3–10 ms pentru conversia datelor. JSI oferă acces sincron direct la obiecte C++ fără serializare, reducând întârzierea la 0.1–0.5 ms. JSI acceptă, de asemenea, transmiterea referințelor la obiecte, nu a copiilor acestora.
Da, JSI oferă un API C++ unitar care este implementat pentru Hermes (implicit în React Native), JavaScriptCore (iOS) și V8 (Android). Dezvoltatorul nu trebuie să scrie cod diferit pentru motoare diferite — Fabric și TurboModules funcționează la fel pe toate motoarele suportate.
Da, React Native oferă un strat de compatibilitate inversă. Modulele native scrise pentru Bridge continuă să funcționeze în noua arhitectură. Cu toate acestea, se recomandă migrarea acestora pe TurboModules pentru a beneficia de avantajele JSI — încărcare leneșă și apeluri sincrone.
Pentru dezvoltarea de zi cu zi — nu. Specificațiile TypeScript ale modulelor native sunt compilate în îmbrăcăminți C++ automat prin Codegen. Cunoștințele de C++ sunt necesare doar la crearea propriilor biblioteci C++ sau la depanarea performanței JSI la nivel de runtime.
JSI rezolvă trei probleme cheie ale Bridge: întârzierea mare din cauza serializării JSON, lipsa apelurilor sincrone și imposibilitatea de a transmite obiecte complexe prin referință. JSI permite, de asemenea, integrarea bibliotecilor C++ direct, fără stratul Java sau Objective-C.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și