JSI (JavaScript Interface) é uma camada de software no React Native que fornece acesso síncrono direto de JavaScript a objetos e funções C++, substituindo a ponte JSON assíncrona Bridge. Ao contrário do seu predecessor, o JSI permite chamar métodos nativos sem serialização de mensagens e passar referências a objetos C++ diretamente para o ambiente JS. De acordo com React Native Team (2025), o JSI proporciona uma aceleração de até 10 vezes na interação JS-código nativo em cenários com intensa troca de dados.
Pontos principais
JSI (JavaScript Interface) é uma camada C++ que fornece ao motor JavaScript (Hermes, JavaScriptCore, V8) a capacidade de acessar diretamente objetos, funções e memória C++. Ao contrário do Bridge, que serializava chamadas em JSON e as passava através de uma fila assíncrona, o JSI permite que o código JS chame métodos C++ de forma síncrona e obtenha o resultado imediatamente.
O JSI foi introduzido no React Native 0.64 como parte da Nova Arquitetura. O objetivo principal era eliminar o gargalo que o Bridge representava: cada interação entre JS e código nativo consumia tempo em serialização, desserialização e passagem pela fila de mensagens. O JSI resolve esse problema dando ao motor JS acesso direto a objetos C++ através de wrappers que implementam as interfaces jsi::Value, jsi::Object e jsi::Function.
O JSI não é uma substituição um a um do Bridge — é uma abordagem fundamentalmente diferente para integração. O Bridge funcionava como uma caixa de correio: JS enviava uma mensagem, ela passava por uma fila, o lado nativo processava e enviava uma resposta. O JSI funciona como um ponteiro: JS obtém uma referência a um objeto C++ e pode chamar seus métodos de forma síncrona, como funções JS normais. Esta é uma diferença fundamental na arquitetura de interação entre dois ambientes.
A necessidade do JSI surgiu das limitações do Bridge original, estabelecido no React Native 2015. À medida que o framework ganhava popularidade e as aplicações se tornavam mais complexas, o problema de desempenho tornou-se evidente: cada chamada a um módulo nativo exigia pelo menos 3–5 ms para serialização. Para operações simples como ler o valor de um sensor ou obter o tamanho da tela, isso era aceitável, mas para animações, trabalho com gráficos e processamento de dados em fluxo — era crítico. A equipe do React Native começou a trabalhar na nova arquitetura em 2019, e o JSI tornou-se sua base.
O JSI é projetado como uma camada de abstração sobre os motores JavaScript. Ele fornece uma API C++ unificada que é implementada para cada motor específico: Hermes, JavaScriptCore (iOS), V8 (Android). Isso significa que os desenvolvedores não precisam se preocupar com as diferenças entre os motores — o Fabric e os TurboModules funcionam da mesma forma independentemente do motor JS usado internamente.
No núcleo do JSI está o conceito de Host Objects (objetos anfitriões) — objetos C++ que são exportados para o ambiente JS como objetos JS nativos. Quando o código JS acessa uma propriedade ou método de tal objeto, o JSI intercepta a chamada e a delega ao método C++ correspondente. Isso ocorre de forma síncrona, na mesma thread, sem troca de contexto e sem alocar memória para uma string JSON.
Cada Host Object implementa a interface jsi::HostObject com os métodos get, set e getPropertyNames. O motor JS chama esses métodos toda vez que uma propriedade do objeto é acessada. Por exemplo, ao chamar NativeModule.someMethod() em JS, o JSI converte esta chamada em uma chamada C++ para o método correspondente do Host Object. O valor de retorno é passado de volta para JS como jsi::Value — um tipo genérico que pode representar um número, string, booleano, objeto ou undefined.
Uma característica importante do JSI é a ausência de fila de mensagens. O Bridge usava uma fila assíncrona: JS enviava uma solicitação, mudava para outras tarefas, o lado nativo processava a solicitação e o resultado era retornado através de um callback. O JSI funciona de forma síncrona: se JS chama um método de módulo nativo através do JSI, a execução do código JS é pausada até que o resultado seja recebido. Isso simplifica a lógica (não é necessário esperar callbacks) e elimina condições de corrida, mas requer cautela — chamadas síncronas longas bloqueiam a thread JS.
Os valores criados através do JSI vivem no runtime do motor JS e são gerenciados pelo coletor de lixo. Quando o código C++ cria um jsi::String ou jsi::Object e o retorna para JS, o ambiente gerencia automaticamente a memória. Se o código C++ quiser manter uma referência a um valor JS entre chamadas, usa-se jsi::Value::getWeak() ou um jsi::Object::setProperty global com uma referência armazenada no objeto raiz do runtime. Isso evita a remoção prematura pelo coletor de lixo.
O JSI não é seguro para threads por padrão. Todas as chamadas de métodos JSI devem ocorrer da thread onde o JS é executado (normalmente a thread JS do React Native). Se um módulo nativo inicia trabalho em segundo plano em uma thread separada, o resultado deve ser retornado através da thread JS usando runOnJS dos TurboModules. Esta limitação é o preço da síncronia e da ausência de serialização.
A diferença entre JSI e Bridge é fundamental e afeta todos os aspectos da interação JS-código nativo. O Bridge era assíncrono, serializava dados em JSON e usava uma fila de mensagens; o JSI é síncrono, trabalha com referências nativas e não requer serialização.
| Parâmetro | Bridge | JSI |
|---|---|---|
| Modelo de chamada | Fila assíncrona | Chamada direta síncrona |
| Serialização | JSON (serialização + desserialização) | Nenhuma (referências diretas a objetos C++) |
| Latência | 3–10 ms por chamada | 0.1–0.5 ms por chamada |
| Tipagem | Dinâmica (via JSON) | Estática (via Codegen) |
| Integração C++ | Apenas através de módulos nativos (Java/ObjC) | Direta, sem intermediários |
| Thread | Thread nativa separada | Thread JS (síncrona) |
De acordo com a React Native Team, a migração do Bridge para o JSI no aplicativo Facebook Marketplace reduziu o tempo de inicialização em 35% e diminuiu o consumo de memória em 20% ao eliminar a duplicação de dados entre os lados JS e nativo.
O Bridge não foi um “erro” — foi uma decisão arquitetural justificada no momento da criação do React Native em 2015. O desenvolvimento nativo para duas plataformas com linguagens diferentes exigia um formato de intercâmbio universal. O JSON como formato de serialização estava disponível em todas as plataformas e permitia unificar a interação. O problema tornou-se evidente mais tarde, quando o React Native começou a ser usado para aplicações complexas com milhares de chamadas a módulos nativos por segundo.
O React Native mantém compatibilidade reversa: os módulos nativos escritos para o Bridge continuam funcionando na nova arquitetura através de uma camada de compatibilidade. No entanto, para novos módulos, recomenda-se usar o JSI diretamente através dos TurboModules. A migração de módulos existentes envolve substituir o protocolo de interação sem alterar a lógica de negócio do módulo.
O JSI é uma camada fundamental sobre a qual todos os componentes da nova arquitetura do React Native são construídos. Sem o JSI, nem o Fabric (o novo renderizador) nem os TurboModules (módulos nativos otimizados) seriam possíveis. O JSI fornece uma forma unificada para o JS interagir com C++ em todos os níveis.
O Fabric é o novo renderizador do React Native que usa o JSI para acesso síncrono a representações C++ da UI. Na arquitetura antiga, a renderização passava pelo Bridge: JS criava elementos React, serializava-os em JSON, enviava-os através do Bridge, o lado nativo desserializava e criava a UI. O Fabric através do JSI cria objetos C++ Shadow Tree diretamente do JS, calcula sincronamente o Layout através do Yoga e passa os quadros prontos para o renderizador nativo — sem uma única serialização.
Os TurboModules são a evolução dos módulos nativos do React Native. Em vez de registrar um módulo no Bridge e chamar seus métodos através de JSON, os TurboModules usam o JSI para carregamento lento e invocação direta. Quando o código JS acessa um módulo pela primeira vez, o JSI cria um Host Object — ele carrega o módulo nativo e expõe seus métodos como funções C++. O carregamento lento significa que o módulo não consome memória até o primeiro acesso — isso é especialmente importante para aplicações com dezenas de módulos nativos, muitos dos quais são usados apenas em telas específicas.
Para trabalhar com o JSI na nova arquitetura, usa-se o Codegen — uma ferramenta que gera bindings C++ a partir de especificações JavaScript. O desenvolvedor descreve a interface do módulo nativo em TypeScript ou Flow, e o Codegen gera código C++ implementando um Host Object compatível com JSI. Isso automatiza o trabalho rotineiro e garante que os tipos nos lados JS e C++ estejam sincronizados.
Vamos ver como é trabalhar com o JSI na prática. Neste exemplo, criamos uma classe C++ simples que é exportada para JS através do JSI e chamamos seu método a partir do código JavaScript no React Native.
// Calculator.h — cabeçalho de classe C++ acessível de JS
class Calculator {
public:
double add(double a, double b) { return a + b; }
double multiply(double a, double b) { return a * b; }
};
A classe Calculator contém dois métodos aritméticos. Precisamos torná-la acessível a partir do JS. Para isso, é criado um Host Object que envolve a Calculator e expõe seus métodos através do JSI.
// CalculatorHostObject.cpp — implementação do 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();
}
};
Neste código, o método get é chamado toda vez que o JS acessa uma propriedade do objeto. Se o nome da propriedade for “add”, uma função C++ é retornada que recebe dois argumentos do JS e chama calc.add(). O valor é retornado como jsi::Value — o JSI converte automaticamente double para um número JS.
Após registrar o Host Object no ambiente JS, a chamada parece uma função JS normal. Todos os tipos são verificados no estágio de geração de código, eliminando erros de incompatibilidade de tipos durante a execução.
// JavaScript — chamando calculadora C++ via JSI
import { Calculator } from 'react-native-calculator'
const result = Calculator.add(5, 3)
console.log(result) // 8 — síncrono, sem atraso
const product = Calculator.multiply(4, 2.5)
console.log(product) // 10 — resultado imediato
Nota: o resultado é retornado imediatamente, sem Promise, sem await, sem callbacks. Esta é uma chamada síncrona que era impossível na arquitetura Bridge. Para operações longas (leitura de arquivo, requisição de rede), devem ser usados padrões assíncronos — o JSI não elimina a necessidade de threads em segundo plano para tarefas pesadas.
Na prática, a maioria dos desenvolvedores não escreve Host Objects JSI manualmente — este trabalho é feito pelo Codegen, que gera wrappers C++ baseados em especificações TypeScript. No entanto, entender como o JSI funciona internamente é necessário para a depuração eficaz de desempenho e ao criar módulos nativos complexos que exigem acesso direto a bibliotecas C++ (Skia, FFmpeg, OpenCV).
Perguntas frequentes
O Bridge funciona de forma assíncrona através de serialização JSON e uma fila de mensagens — cada chamada leva 3–10 ms para conversão de dados. O JSI fornece acesso direto síncrono a objetos C++ sem serialização, reduzindo a latência para 0.1–0.5 ms. O JSI também suporta passar referências de objetos em vez de cópias.
Sim, o JSI fornece uma API C++ unificada implementada para Hermes (padrão do React Native), JavaScriptCore (iOS) e V8 (Android). Os desenvolvedores não precisam escrever código diferente para motores diferentes — o Fabric e os TurboModules funcionam igualmente em todos os motores suportados.
Sim, o React Native fornece uma camada de compatibilidade reversa. Módulos nativos escritos para o Bridge continuam funcionando na nova arquitetura. No entanto, recomenda-se migrá-los para os TurboModules para obter os benefícios do JSI — carregamento lento e chamadas síncronas.
Para o desenvolvimento diário — não. As especificações TypeScript dos módulos nativos são compiladas em bindings C++ automaticamente através do Codegen. O conhecimento de C++ é necessário apenas ao criar bibliotecas C++ personalizadas ou ao depurar o desempenho do JSI no nível do runtime.
O JSI resolve três problemas principais do Bridge: alta latência devido à serialização JSON, falta de chamadas síncronas e impossibilidade de passar objetos complexos por referência. O JSI também permite integrar bibliotecas C++ diretamente, sem intermediários Java ou Objective-C.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também