JSI: что это такое, принцип работы и архитектура

Автор: IT Sectr Опубликовано: 2026-06-04 Время чтения: 10 мин

JSI (JavaScript Interface) — это программный слой в React Native, который предоставляет прямой синхронный доступ из JavaScript к C++ объектам и функциям, заменяя асинхронный JSON-мост Bridge. В отличие от предшественника, JSI позволяет вызывать нативные методы без сериализации сообщений и передавать ссылки на C++ объекты напрямую в JS-среду. По данным React Native Team (2025), JSI обеспечивает до 10-кратного ускорения взаимодействия JS с нативным кодом в сценариях с интенсивным обменом данными.

Главное

  • JSI — JavaScript Interface, обеспечивающий синхронный доступ из JS к нативному C++ коду
  • Прямой доступ устраняет необходимость сериализации в JSON и асинхронной очереди сообщений
  • Производительность взаимодействия JS и нативного кода возрастает в 5–10 раз
  • Архитектура JSI лежит в основе Fabric и TurboModules в новой архитектуре React Native
  • C++ интеграция позволяет подключать произвольные C++ библиотеки без нативных обёрток

Что такое JSI?

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 стала её фундаментом.

Поддержка JavaScript-движков

JSI спроектирована как абстракция над JavaScript-движками. Она предоставляет единый C++ API, который реализуется для каждого конкретного движка: Hermes, JavaScriptCore (iOS), V8 (Android). Это означает, что разработчику не нужно заботиться о различиях между движками — Fabric и TurboModules работают одинаково независимо от того, какой JS-движок используется под капотом.

Как работает JSI?

В основе 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

Значения, созданные через 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 vs Bridge: сравнение

Разница между JSI и Bridge носит фундаментальный характер и затрагивает все аспекты взаимодействия JS с нативным кодом. Bridge был асинхронным, сериализовал данные в JSON и использовал очередь сообщений; JSI — синхронный, работает с нативными ссылками и не требует сериализации.

ПараметрBridgeJSI
Модель вызоваАсинхронная очередьСинхронный прямой вызов
Сериализация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 был необходим

Bridge не был «ошибкой» — он был архитектурным решением, оправданным на момент создания React Native в 2015 году. Нативной разработки для двух платформ с разными языками требовался универсальный формат обмена. JSON как формат сериализации был доступен на всех платформах и позволял унифицировать взаимодействие. Проблема проявилась позже, когда React Native начали использовать для сложных приложений с тысячами вызовов нативных модулей в секунду.

Обратная совместимость

React Native сохраняет обратную совместимость: нативные модули, написанные для Bridge, продолжают работать в новой архитектуре через слой совместимости. Однако для новых модументов рекомендуется сразу использовать JSI через TurboModules. Миграция существующих модулей — это замена протокола взаимодействия без изменения бизнес-логики самого модуля.

JSI в архитектуре React Native

JSI является фундаментальным слоем, на котором построены все компоненты новой архитектуры React Native. Без JSI невозможна работа ни Fabric (новый рендерер), ни TurboModules (оптимизированные нативные модули). JSI обеспечивает единый способ взаимодействия JS с C++ на всех уровнях.

Fabric и JSI

Fabric — новый рендерер React Native, который использует JSI для синхронного доступа к C++ представлениям UI. В старой архитектуре рендеринг проходил через Bridge: JS создавал React-элементы, сериализовал их в JSON, отправлял через Bridge, нативная сторона десериализовала и создавала UI. Fabric через JSI создаёт C++ объекты Shadow Tree прямо из JS, синхронно вычисляет Layout через Yoga и передаёт готовые фреймы нативному рендереру — без единой сериализации.

TurboModules и JSI

TurboModules — это эволюция нативных модулей React Native. Вместо того чтобы регистрировать модуль в Bridge и вызывать его методы через JSON, TurboModules использует JSI для ленивой загрузки и прямого вызова. Когда JS-код впервые обращается к модулю, JSI создаёт Host Object — он загружает нативный модуль и предоставляет его методы как C++ функции. Ленивая загрузка означает, что модуль не потребляет память до первого обращения — это особенно важно для приложений с десятками нативных модулей, многие из которых используются только в определённых экранах.

Кодогенерация через JSI

Для работы с JSI в новой архитектуре используется Codegen — инструмент, который генерирует C++ обвязки из JavaScript-спецификаций. Разработчик описывает интерфейс нативного модуля на TypeScript или Flow, а Codegen генерирует C++ код, реализующий JSI-совместимый Host Object. Это автоматизирует рутинную работу и гарантирует, что типы на стороне JS и C++ синхронизированы.

Примеры кода с JSI

Рассмотрим, как выглядит работа с JSI на практике. В этом примере создаётся простой C++ класс, который экспортируется в JS через JSI, и вызывается его метод из JavaScript-кода React Native.

cpp
// 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.

cpp
// 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-число.

Вызов из JavaScript

После регистрации Host Object в JS-среде, вызов выглядит как обычная 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).

Часто задаваемые вопросы

Чем JSI отличается от Bridge в React Native?

Bridge работает асинхронно через JSON-сериализацию и очередь сообщений — каждый вызов требует 3–10 мс на преобразование данных. JSI предоставляет синхронный прямой доступ к C++ объектам без сериализации, снижая задержку до 0.1–0.5 мс. JSI также поддерживает передачу ссылок на объекты, а не их копий.

Поддерживает ли JSI все JavaScript-движки?

Да, JSI предоставляет единый C++ API, который реализован для Hermes (React Native по умолчанию), JavaScriptCore (iOS) и V8 (Android). Разработчику не нужно писать разный код для разных движков — Fabric и TurboModules работают одинаково на всех поддерживаемых движках.

Можно ли использовать старые нативные модули с JSI?

Да, React Native предоставляет слой обратной совместимости. Нативные модули, написанные для Bridge, продолжают работать в новой архитектуре. Однако рекомендуется мигрировать их на TurboModules для получения преимуществ JSI — ленивой загрузки и синхронных вызовов.

Требует ли JSI знаний C++?

Для повседневной разработки — нет. TypeScript-спецификации нативных модулей компилируются в C++ обвязки автоматически через Codegen. Знание C++ необходимо только при создании собственных C++ библиотек или при отладке производительности JSI на уровне рантайма.

Какие проблемы решает JSI?

JSI решает три ключевые проблемы Bridge: высокую задержку из-за JSON-сериализации, отсутствие синхронных вызовов и невозможность передавать сложные объекты по ссылке. Также JSI позволяет интегрировать C++ библиотеки напрямую, без Java или Objective-C прослойки.

Итоги

  • JSI (JavaScript Interface) — технология прямого синхронного доступа из JavaScript к C++ объектам в React Native
  • Архитектура JSI основана на Host Objects — C++ объектах, которые экспортируются в JS как нативные JS-объекты
  • Производительность вызовов через JSI в 10–50 раз выше, чем через Bridge, за счёт отсутствия сериализации
  • Fabric и TurboModules — ключевые компоненты новой архитектуры React Native, построенные поверх JSI
  • Синхронность JSI упрощает логику кода, но требует осторожности при длительных операциях
  • C++ интеграция позволяет подключать любые нативные библиотеки без платформенных обёрток
  • Используйте JSI для высокопроизводительных нативных модулей и мигрируйте существующие с Bridge

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также