Aller au contenu
useffect.sh
Planifier 30 min avec un senior
Architecture

JSI (JavaScript Interface)

L’API C++ qui laisse JavaScript tenir des références directes sur des objets natifs, sans sérialisation : la fondation de la New Architecture.

Définition

JSI, pour JavaScript Interface, est une API C++ légère qui permet à un moteur JavaScript (Hermes, ou JavaScriptCore) d’exposer des objets natifs directement à JavaScript, et inversement. Un objet JavaScript peut tenir une référence vers un objet C++ et appeler ses méthodes de façon synchrone, sans passer par une file de messages JSON. C’est ce qui remplace le bridge asynchrone de l’ancienne architecture de React Native, où chaque appel natif était sérialisé, mis en file, puis désérialisé de l’autre côté. Fabric, les Turbo Modules, Reanimated, Nitro Modules ou VisionCamera sont tous construits dessus. JSI est aussi indépendant du moteur : le même code natif fonctionne avec Hermes ou JSC. Vous y êtes confronté quand vous lisez la doc d’une librairie « JSI-based », que vous écrivez un HostObject en C++, ou que vous cherchez à comprendre pourquoi un appel natif peut maintenant être synchrone.

Dans une vraie app

Dans la pratique, un dev d’app n’écrit presque jamais de JSI à la main : il le consomme via les Turbo Modules, l’Expo Modules API ou Nitro. Le concept compte quand même pour lire un crash. Une stack trace qui passe par jsi::Runtime, HostObject ou facebook::jsi::Function indique que le problème est dans la couche d’appel natif, pas dans votre JavaScript. Et un appel JSI synchrone bloque le thread JS tant qu’il n’a pas rendu la main : une méthode native lente appelée dans un onScroll se voit immédiatement.

Le piège classique vient du threading. Un objet JSI appartient au runtime qui l’a créé ; y toucher depuis un autre thread (une callback réseau, un gestionnaire natif) corrompt la mémoire ou crashe sans message utile. Les librairies sérieuses passent par CallInvoker pour revenir sur le thread JS. Autre cas : les workers de Reanimated ont leur propre runtime JSI, d’où l’impossibilité d’appeler une fonction du thread JS depuis un worklet sans scheduleOnRN (runOnJS avant Reanimated 4).

Ce que je regarde : le moteur réellement utilisé (global.HermesInternal), les librairies qui déclarent du C++ dans leur podspec ou CMakeLists.txt, et si le projet mélange des modules bridge en interop et des modules JSI qui touchent les mêmes ressources natives.

Sources

Les 35 termes du glossaire

Un de ces sujets bloque votre app ?

30 minutes avec un senior pour regarder le problème dans votre code. Gratuit.