JSI: cos'è, principio di funzionamento e architettura

Autore: IT Sectr Pubblicato: 2026-06-04 Tempo di lettura: 10 min

JSI (JavaScript Interface) è un livello software in React Native che fornisce accesso sincrono diretto da JavaScript a oggetti e funzioni C++, sostituendo il ponte JSON asincrono Bridge. A differenza del suo predecessore, JSI consente di chiamare metodi nativi senza serializzazione dei messaggi e di passare riferimenti a oggetti C++ direttamente nell'ambiente JS. Secondo React Native Team (2025), JSI fornisce un'accelerazione fino a 10 volte dell'interazione JS-codice nativo in scenari con intenso scambio di dati.

Punti chiave

  • JSI — JavaScript Interface che fornisce accesso sincrono da JS al codice nativo C++
  • Accesso diretto elimina la necessità di serializzazione JSON e coda messaggi asincrona
  • Prestazioni dell'interazione JS-codice nativo aumentano di 5–10 volte
  • Architettura JSI è il fondamento di Fabric e TurboModules nella nuova architettura React Native
  • Integrazione C++ permette di connettere librerie C++ arbitrarie senza wrapper nativi

Cos'è JSI?

JSI (JavaScript Interface) è un livello C++ che fornisce al motore JavaScript (Hermes, JavaScriptCore, V8) la capacità di accedere direttamente a oggetti, funzioni e memoria C++. A differenza di Bridge, che serializzava le chiamate in JSON e le passava attraverso una coda asincrona, JSI consente al codice JS di chiamare metodi C++ in modo sincrono e ottenere il risultato immediatamente.

JSI è stato introdotto in React Native 0.64 come parte della nuova architettura. L'obiettivo principale era eliminare il collo di bottiglia che Bridge rappresentava: ogni interazione tra JS e codice nativo consumava tempo in serializzazione, deserializzazione e passaggio attraverso la coda dei messaggi. JSI risolve questo problema dando al motore JS accesso diretto agli oggetti C++ attraverso wrapper che implementano le interfacce jsi::Value, jsi::Object e jsi::Function.

JSI non è una sostituzione uno a uno di Bridge — è un approccio fondamentalmente diverso all'integrazione. Bridge funzionava come una cassetta postale: JS inviava un messaggio, passava attraverso una coda, il lato nativo lo elaborava e inviava una risposta. JSI funziona come un puntatore: JS ottiene un riferimento a un oggetto C++ e può chiamare i suoi metodi in modo sincrono, come normali funzioni JS. Questa è una differenza fondamentale nell'architettura di interazione tra due ambienti.

Storia della creazione

La necessità di JSI è nata dalle limitazioni del Bridge originale, stabilito in React Native 2015. Con la crescente popolarità del framework e la maggiore complessità delle applicazioni, il problema delle prestazioni è diventato evidente: ogni chiamata a un modulo nativo richiedeva almeno 3–5 ms per la serializzazione. Per operazioni semplici come leggere il valore di un sensore o ottenere le dimensioni dello schermo, questo era accettabile, ma per animazioni, lavoro grafico ed elaborazione di dati in streaming — era critico. Il team di React Native ha iniziato a lavorare sulla nuova architettura nel 2019 e JSI ne è diventato il fondamento.

Supporto motori JavaScript

JSI è progettato come livello di astrazione sopra i motori JavaScript. Fornisce un'API C++ unificata che viene implementata per ogni motore specifico: Hermes, JavaScriptCore (iOS), V8 (Android). Ciò significa che gli sviluppatori non devono preoccuparsi delle differenze tra i motori — Fabric e TurboModules funzionano allo stesso modo indipendentemente dal motore JS utilizzato sotto il cofano.

Come funziona JSI?

Al centro di JSI c'è il concetto di Host Objects (oggetti ospite) — oggetti C++ che vengono esportati nell'ambiente JS come oggetti JS nativi. Quando il codice JS accede a una proprietà o metodo di tale oggetto, JSI intercetta la chiamata e la delega al metodo C++ corrispondente. Ciò avviene in modo sincrono, nello stesso thread, senza cambio di contesto e senza allocare memoria per una stringa JSON.

Ogni oggetto ospite implementa l'interfaccia jsi::HostObject con i metodi get, set e getPropertyNames. Il motore JS chiama questi metodi ogni volta che viene acceduta una proprietà dell'oggetto. Ad esempio, quando si chiama NativeModule.someMethod() in JS, JSI converte questa chiamata in una chiamata C++ al metodo corrispondente dell'oggetto ospite. Il valore restituito viene passato a JS come jsi::Value — un tipo generico che può rappresentare un numero, stringa, booleano, oggetto o undefined.

Una caratteristica importante di JSI è l'assenza di una coda di messaggi. Bridge utilizzava una coda asincrona: JS inviava una richiesta, passava ad altre attività, il lato nativo elaborava la richiesta e il risultato veniva restituito tramite un callback. JSI funziona in modo sincrono: se JS chiama un metodo di modulo nativo attraverso JSI, l'esecuzione del codice JS viene sospesa fino al ricevimento del risultato. Ciò semplifica la logica (non c'è bisogno di attendere callback) ed elimina le condizioni di competizione, ma richiede cautela — le chiamate sincrone lunghe bloccano il thread JS.

Ciclo di vita dei valori JSI

I valori creati attraverso JSI vivono nel runtime del motore JS e sono gestiti dal garbage collector. Quando il codice C++ crea un jsi::String o jsi::Object e lo restituisce a JS, l'ambiente gestisce automaticamente la memoria. Se il codice C++ vuole mantenere un riferimento a un valore JS tra le chiamate, viene utilizzato jsi::Value::getWeak() o un jsi::Object::setProperty globale con un riferimento memorizzato sull'oggetto radice del runtime. Ciò impedisce la rimozione anticipata da parte del garbage collector.

Sicurezza dei thread

JSI non è thread-safe per impostazione predefinita. Tutte le chiamate ai metodi JSI devono avvenire dal thread in cui JS viene eseguito (di solito il thread JS di React Native). Se un modulo nativo avvia un lavoro in background in un thread separato, il risultato deve essere restituito attraverso il thread JS utilizzando runOnJS dei TurboModules. Questa limitazione è il prezzo della sincronia e dell'assenza di serializzazione.

JSI vs Bridge: confronto

La differenza tra JSI e Bridge è fondamentale e riguarda tutti gli aspetti dell'interazione JS-codice nativo. Bridge era asincrono, serializzava i dati in JSON e utilizzava una coda di messaggi; JSI è sincrono, lavora con riferimenti nativi e non richiede serializzazione.

ParametroBridgeJSI
Modello di chiamataCoda asincronaChiamata diretta sincrona
SerializzazioneJSON (serializzazione + deserializzazione)Nessuna (riferimenti diretti a oggetti C++)
Latenza3–10 ms per chiamata0.1–0.5 ms per chiamata
TipizzazioneDinamica (via JSON)Statica (via Codegen)
Integrazione C++Solo tramite moduli nativi (Java/ObjC)Diretta, senza intermediari
ThreadThread nativo separatoThread JS (sincrono)

Secondo React Native Team, la migrazione da Bridge a JSI nell'app Facebook Marketplace ha ridotto il tempo di avvio del 35% e diminuito il consumo di memoria del 20% eliminando la duplicazione dei dati tra i lati JS e nativo.

Quando Bridge era necessario

Bridge non era un “'errore” — era una decisione architetturale giustificata al momento della creazione di React Native nel 2015. Lo sviluppo nativo per due piattaforme con linguaggi diversi richiedeva un formato di scambio universale. JSON come formato di serializzazione era disponibile su tutte le piattaforme e permetteva di unificare l'interazione. Il problema è diventato evidente in seguito, quando React Native ha iniziato a essere utilizzato per applicazioni complesse con migliaia di chiamate a moduli nativi al secondo.

Retrocompatibilità

React Native mantiene la retrocompatibilità: i moduli nativi scritti per Bridge continuano a funzionare nella nuova architettura attraverso un livello di compatibilità. Tuttavia, per i nuovi moduli si consiglia di utilizzare JSI direttamente attraverso i TurboModules. La migrazione dei moduli esistenti comporta la sostituzione del protocollo di interazione senza modificare la logica di business del modulo stesso.

JSI nell'architettura React Native

JSI è un livello fondamentale su cui sono costruiti tutti i componenti della nuova architettura React Native. Senza JSI, né Fabric (il nuovo renderer) né TurboModules (moduli nativi ottimizzati) sarebbero possibili. JSI fornisce un modo unificato per JS di interagire con C++ a tutti i livelli.

Fabric e JSI

Fabric è il nuovo renderer di React Native che utilizza JSI per l'accesso sincrono alle rappresentazioni C++ dell'interfaccia utente. Nella vecchia architettura, il rendering passava attraverso Bridge: JS creava elementi React, li serializzava in JSON, li inviava attraverso Bridge, il lato nativo deserializzava e creava l'interfaccia utente. Fabric attraverso JSI crea oggetti C++ Shadow Tree direttamente da JS, calcola in modo sincrono il Layout tramite Yoga e passa i frame pronti al renderer nativo — senza una singola serializzazione.

TurboModules e JSI

TurboModules è l'evoluzione dei moduli nativi di React Native. Invece di registrare un modulo in Bridge e chiamare i suoi metodi attraverso JSON, TurboModules utilizza JSI per il caricamento lento e l'invocazione diretta. Quando il codice JS accede per la prima volta a un modulo, JSI crea un oggetto ospite — carica il modulo nativo ed espone i suoi metodi come funzioni C++. Il caricamento lento significa che il modulo non consuma memoria fino al primo accesso — questo è particolarmente importante per applicazioni con decine di moduli nativi, molti dei quali vengono utilizzati solo in schermate specifiche.

Generazione di codice attraverso JSI

Per lavorare con JSI nella nuova architettura, viene utilizzato Codegen — uno strumento che genera binding C++ da specifiche JavaScript. Lo sviluppatore descrive l'interfaccia del modulo nativo in TypeScript o Flow, e Codegen genera codice C++ che implementa un oggetto ospite compatibile con JSI. Ciò automatizza il lavoro di routine e garantisce che i tipi sui lati JS e C++ siano sincronizzati.

Esempi di codice con JSI

Vediamo come appare il lavoro con JSI nella pratica. In questo esempio, creiamo una semplice classe C++ che viene esportata in JS attraverso JSI e chiamiamo il suo metodo dal codice JavaScript in React Native.

cpp
// Calculator.h — header di classe C++ accessibile da JS
class Calculator {
public:
    double add(double a, double b) { return a + b; }
    double multiply(double a, double b) { return a * b; }
};

La classe Calculator contiene due metodi aritmetici. Dobbiamo renderla accessibile da JS. Per fare ciò, viene creato un oggetto ospite che incapsula Calculator ed espone i suoi metodi attraverso JSI.

cpp
// CalculatorHostObject.cpp — implementazione wrapper 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();
    }
};

In questo codice, il metodo get viene chiamato ogni volta che JS accede a una proprietà dell'oggetto. Se il nome della proprietà è “add”, viene restituita una funzione C++ che riceve due argomenti da JS e chiama calc.add(). Il valore viene restituito come jsi::Value — JSI converte automaticamente double in un numero JS.

Chiamata da JavaScript

Dopo aver registrato l'oggetto ospite nell'ambiente JS, la chiamata appare come una normale funzione JS. Tutti i tipi vengono verificati nella fase di generazione del codice, eliminando errori di mancata corrispondenza dei tipi durante l'esecuzione.

js
// JavaScript — chiamata alla calcolatrice C++ via JSI
import { Calculator } from 'react-native-calculator'

const result = Calculator.add(5, 3)
console.log(result) // 8 — sincrono, nessun ritardo

const product = Calculator.multiply(4, 2.5)
console.log(product) // 10 — risultato immediato

Nota: il risultato viene restituito immediatamente, senza Promise, senza await, senza callback. Questa è una chiamata sincrona che era impossibile nell'architettura Bridge. Per operazioni lunghe (lettura di file, richiesta di rete), dovrebbero essere utilizzati pattern asincroni — JSI non elimina la necessità di thread in background per attività pesanti.

In pratica, la maggior parte degli sviluppatori non scrive oggetti ospite JSI manualmente — questo lavoro viene svolto da Codegen, che genera wrapper C++ basati su specifiche TypeScript. Tuttavia, comprendere come JSI funziona internamente è necessario per un debugging efficace delle prestazioni e durante la creazione di moduli nativi complessi che richiedono accesso diretto a librerie C++ (Skia, FFmpeg, OpenCV).

Domande frequenti

In che modo JSI differisce da Bridge in React Native?

Bridge funziona in modo asincrono attraverso la serializzazione JSON e una coda di messaggi — ogni chiamata richiede 3–10 ms per la conversione dei dati. JSI fornisce accesso diretto sincrono agli oggetti C++ senza serializzazione, riducendo la latenza a 0.1–0.5 ms. JSI supporta anche il passaggio di riferimenti a oggetti anziché copie.

JSI supporta tutti i motori JavaScript?

Sì, JSI fornisce un'API C++ unificata implementata per Hermes (predefinito React Native), JavaScriptCore (iOS) e V8 (Android). Gli sviluppatori non devono scrivere codice diverso per motori diversi — Fabric e TurboModules funzionano allo stesso modo su tutti i motori supportati.

Si possono usare vecchi moduli nativi con JSI?

Sì, React Native fornisce un livello di retrocompatibilità. I moduli nativi scritti per Bridge continuano a funzionare nella nuova architettura. Tuttavia, si consiglia di migrarli ai TurboModules per ottenere i vantaggi di JSI — caricamento lento e chiamate sincrone.

JSI richiede conoscenze di C++?

Per lo sviluppo quotidiano — no. Le specifiche TypeScript dei moduli nativi vengono compilate automaticamente in binding C++ attraverso Codegen. La conoscenza del C++ è necessaria solo durante la creazione di librerie C++ personalizzate o durante il debug delle prestazioni di JSI a livello di runtime.

Quali problemi risolve JSI?

JSI risolve tre problemi chiave di Bridge: elevata latenza dovuta alla serializzazione JSON, mancanza di chiamate sincrone e impossibilità di passare oggetti complessi per riferimento. JSI consente inoltre di integrare librerie C++ direttamente, senza intermediari Java o Objective-C.

Riepilogo

  • JSI (JavaScript Interface) — tecnologia di accesso diretto sincrono da JavaScript a oggetti C++ in React Native
  • Architettura JSI si basa su oggetti ospite — oggetti C++ esportati in JS come oggetti JS nativi
  • Prestazioni delle chiamate attraverso JSI sono 10–50 volte superiori a Bridge, grazie all'assenza di serializzazione
  • Fabric e TurboModules — componenti chiave della nuova architettura React Native, costruiti sopra JSI
  • Sincronia di JSI semplifica la logica del codice ma richiede cautela con operazioni lunghe
  • Integrazione C++ permette di connettere qualsiasi libreria nativa senza wrapper di piattaforma
  • Usa JSI per moduli nativi ad alte prestazioni e migra quelli esistenti da Bridge

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche