JSI (JavaScript Interface) — это программный слой в React Native, который предоставляет прямой синхронный доступ из JavaScript к C++ объектам и функциям, заменяя асинхронный JSON-мост Bridge. В отличие от предшественника, JSI позволяет вызывать нативные методы без сериализации сообщений и передавать ссылки на C++ объекты напрямую в JS-среду. По данным React Native Team (2025), JSI обеспечивает до 10-кратного ускорения взаимодействия JS с нативным кодом в сценариях с интенсивным обменом данными.
Главное
JSI (JavaScript Interface) — это C++ слой, который предоставляет JavaScript-движку (Hermes, JavaScriptCore, V8) возможность напрямую обращаться к C++ объектам, функциям и памяти. В отличие от Bridge, который сериализовал вызовы в JSON и передавал их через асинхронную очередь, JSI позволяет JS-коду синхронно вызывать C++ методы и получать результат немедленно.
JSI была представлена в React Native 0.64 как часть новой архитектуры (New Architecture). Основная цель — устранить узкое место, которым был Bridge: на каждое взаимодействие между JS и нативным кодом тратилось время на сериализацию, десериализацию и передачу через очередь сообщений. JSI решает эту проблему, предоставляя JS-движку прямой доступ к C++ объектам через обёртки, реализующие интерфейс jsi::Value, jsi::Object и jsi::Function.
JSI не является заменой Bridge «один в один» — это принципиально иной подход к интеграции. Bridge работал как почтовый ящик: JS отправлял сообщение, оно проходило через очередь, нативная сторона его обрабатывала и отправляла ответ. JSI работает как указатель: JS получает ссылку на C++ объект и может вызывать его методы синхронно, как обычные JS-функции. Это кардинальное отличие в архитектуре взаимодействия двух сред.
Необходимость в JSI возникла из-за ограничений оригинального Bridge, заложенного в React Native 2015 года. По мере роста популярности фреймворка и усложнения приложений стала очевидной проблема производительности: каждый вызов нативного модуля требовал минимум 3–5 мс на сериализацию. Для простых операций, таких как чтение значения сенсора или получение размера экрана, это было приемлемо, но для анимаций, работы с графикой и потоковой обработки данных — критично. Команда React Native начала работу над новой архитектурой в 2019 году, и JSI стала её фундаментом.
JSI спроектирована как абстракция над JavaScript-движками. Она предоставляет единый C++ API, который реализуется для каждого конкретного движка: Hermes, JavaScriptCore (iOS), V8 (Android). Это означает, что разработчику не нужно заботиться о различиях между движками — Fabric и TurboModules работают одинаково независимо от того, какой JS-движок используется под капотом.
В основе JSI лежит концепция Host Objects — C++ объектов, которые экспортируются в JS-среду как нативные JS-объекты. Когда JS-код обращается к свойству или методу такого объекта, JSI перехватывает вызов и делегирует его соответствующему C++ методу. Это происходит синхронно, в том же потоке, без переключения контекста и без выделения памяти под JSON-строку.
Каждый Host Object реализует интерфейс jsi::HostObject с методами get, set и getPropertyNames. JS-движок вызывает эти методы при каждом обращении к свойствам объекта. Например, при вызове NativeModule.someMethod() в JS, JSI преобразует этот вызов в C++ вызов соответствующего метода Host Object. Возвращаемое значение передаётся обратно в JS как jsi::Value — обобщённый тип, который может представлять число, строку, булево значение, объект или undefined.
Важная особенность JSI — отсутствие очереди сообщений. Bridge использовал асинхронную очередь: JS отправлял запрос, переключался на другие задачи, нативная сторона обрабатывала запрос, и результат возвращался через колбэк. JSI работает синхронно: если JS вызывает метод нативного модуля через JSI, выполнение JS-кода приостанавливается до получения результата. Это упрощает логику (не нужно ждать колбэков) и устраняет race conditions, но требует осторожности — длительные синхронные вызовы блокируют JS-поток.
Значения, созданные через JSI, живут в runtime JS-движка и управляются сборщиком мусора. Когда C++ код создаёт jsi::String или jsi::Object и возвращает его в JS, среда автоматически управляет памятью. Если C++ код хочет сохранить ссылку на JS-значение между вызовами, используется jsi::Value::getWeak() или глобальный jsi::Object::setProperty с сохранением ссылки на корневом объекте runtime. Это предотвращает преждевременное удаление сборщиком мусора.
JSI не является потокобезопасным по умолчанию. Все вызовы методов JSI должны происходить из потока, в котором выполняется JS (обычно это JS-поток React Native). Если нативный модуль запускает фоновую работу в отдельном потоке, результат должен передаваться обратно через JS-поток с помощью вызова runOnJS из TurboModules. Это ограничение — плата за синхронность и отсутствие сериализации.
Разница между JSI и Bridge носит фундаментальный характер и затрагивает все аспекты взаимодействия JS с нативным кодом. Bridge был асинхронным, сериализовал данные в JSON и использовал очередь сообщений; JSI — синхронный, работает с нативными ссылками и не требует сериализации.
| Параметр | Bridge | JSI |
|---|---|---|
| Модель вызова | Асинхронная очередь | Синхронный прямой вызов |
| Сериализация | JSON (сериализация + десериализация) | Нет (прямые ссылки на C++ объекты) |
| Задержка | 3–10 мс на вызов | 0.1–0.5 мс на вызов |
| Типизация | Динамическая (через JSON) | Статическая (через Codegen) |
| C++ интеграция | Только через нативные модули (Java/ObjC) | Прямая, без посредников |
| Поток | Отдельный нативный поток | JS-поток (синхронно) |
По данным React Native Team, миграция с Bridge на JSI в приложении Facebook Marketplace сократила время запуска на 35% и уменьшила потребление памяти на 20% за счёт устранения дублирования данных между JS и нативной сторонами.
Bridge не был «ошибкой» — он был архитектурным решением, оправданным на момент создания React Native в 2015 году. Нативной разработки для двух платформ с разными языками требовался универсальный формат обмена. JSON как формат сериализации был доступен на всех платформах и позволял унифицировать взаимодействие. Проблема проявилась позже, когда React Native начали использовать для сложных приложений с тысячами вызовов нативных модулей в секунду.
React Native сохраняет обратную совместимость: нативные модули, написанные для Bridge, продолжают работать в новой архитектуре через слой совместимости. Однако для новых модументов рекомендуется сразу использовать JSI через TurboModules. Миграция существующих модулей — это замена протокола взаимодействия без изменения бизнес-логики самого модуля.
JSI является фундаментальным слоем, на котором построены все компоненты новой архитектуры React Native. Без JSI невозможна работа ни Fabric (новый рендерер), ни TurboModules (оптимизированные нативные модули). JSI обеспечивает единый способ взаимодействия JS с C++ на всех уровнях.
Fabric — новый рендерер React Native, который использует JSI для синхронного доступа к C++ представлениям UI. В старой архитектуре рендеринг проходил через Bridge: JS создавал React-элементы, сериализовал их в JSON, отправлял через Bridge, нативная сторона десериализовала и создавала UI. Fabric через JSI создаёт C++ объекты Shadow Tree прямо из JS, синхронно вычисляет Layout через Yoga и передаёт готовые фреймы нативному рендереру — без единой сериализации.
TurboModules — это эволюция нативных модулей React Native. Вместо того чтобы регистрировать модуль в Bridge и вызывать его методы через JSON, TurboModules использует JSI для ленивой загрузки и прямого вызова. Когда JS-код впервые обращается к модулю, JSI создаёт Host Object — он загружает нативный модуль и предоставляет его методы как C++ функции. Ленивая загрузка означает, что модуль не потребляет память до первого обращения — это особенно важно для приложений с десятками нативных модулей, многие из которых используются только в определённых экранах.
Для работы с JSI в новой архитектуре используется Codegen — инструмент, который генерирует C++ обвязки из JavaScript-спецификаций. Разработчик описывает интерфейс нативного модуля на TypeScript или Flow, а Codegen генерирует C++ код, реализующий JSI-совместимый Host Object. Это автоматизирует рутинную работу и гарантирует, что типы на стороне JS и C++ синхронизированы.
Рассмотрим, как выглядит работа с JSI на практике. В этом примере создаётся простой C++ класс, который экспортируется в JS через JSI, и вызывается его метод из JavaScript-кода React Native.
// Calculator.h — C++ class header accessible from JS
class Calculator {
public:
double add(double a, double b) { return a + b; }
double multiply(double a, double b) { return a * b; }
};
Класс Calculator содержит два арифметических метода. Нам нужно сделать его доступным из JS. Для этого создаётся Host Object, который оборачивает Calculator и предоставляет его методы через JSI.
// CalculatorHostObject.cpp — JSI wrapper implementation
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();
}
};
В этом коде метод get вызывается всякий раз, когда JS обращается к свойству объекта. Если имя свойства — "add", возвращается C++ функция, которая принимает два аргумента из JS и вызывает calc.add(). Значение возвращается как jsi::Value — JSI автоматически преобразует double в JS-число.
После регистрации Host Object в JS-среде, вызов выглядит как обычная JS-функция. Все типы проверяются на этапе кодогенерации, что исключает ошибки несоответствия типов во время выполнения.
// JavaScript — calling C++ calculator via JSI
import { Calculator } from 'react-native-calculator'
const result = Calculator.add(5, 3)
console.log(result) // 8 — synchronous, no delay
const product = Calculator.multiply(4, 2.5)
console.log(product) // 10 — immediate result
Обратите внимание: результат возвращается немедленно, без Promise, без await, без колбэков. Это синхронный вызов, который был невозможен в архитектуре Bridge. Для длительных операций (чтение файла, сетевой запрос) следует использовать асинхронные паттерны Java — JSI не отменяет необходимость в фоновых потоках для тяжёлых задач.
На практике большинство разработчиков не пишут JSI Host Objects вручную — эту работу выполняет Codegen, который генерирует C++ обёртки на основе TypeScript-спецификаций. Однако понимание того, как работает JSI под капотом, необходимо для эффективной отладки производительности и при создании сложных нативных модулей, требующих прямого доступа к C++ библиотекам (Skia, FFmpeg, OpenCV).
Часто задаваемые вопросы
Bridge работает асинхронно через JSON-сериализацию и очередь сообщений — каждый вызов требует 3–10 мс на преобразование данных. JSI предоставляет синхронный прямой доступ к C++ объектам без сериализации, снижая задержку до 0.1–0.5 мс. JSI также поддерживает передачу ссылок на объекты, а не их копий.
Да, JSI предоставляет единый C++ API, который реализован для Hermes (React Native по умолчанию), JavaScriptCore (iOS) и V8 (Android). Разработчику не нужно писать разный код для разных движков — Fabric и TurboModules работают одинаково на всех поддерживаемых движках.
Да, React Native предоставляет слой обратной совместимости. Нативные модули, написанные для Bridge, продолжают работать в новой архитектуре. Однако рекомендуется мигрировать их на TurboModules для получения преимуществ JSI — ленивой загрузки и синхронных вызовов.
Для повседневной разработки — нет. TypeScript-спецификации нативных модулей компилируются в C++ обвязки автоматически через Codegen. Знание C++ необходимо только при создании собственных C++ библиотек или при отладке производительности JSI на уровне рантайма.
JSI решает три ключевые проблемы Bridge: высокую задержку из-за JSON-сериализации, отсутствие синхронных вызовов и невозможность передавать сложные объекты по ссылке. Также JSI позволяет интегрировать C++ библиотеки напрямую, без Java или Objective-C прослойки.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также