React Native JSI: 직접 연결은 무엇을 해결하고 무엇을 남기는가
JavaScript Interface가 JavaScript 런타임과 C++ 기능을 연결하는 역할을 이해하고, 직접 호출을 자동 성능·백그라운드 실행 보장으로 오해하지 않는 판단 기준을 세운다.
목차
표준·구현·측정·해석 표시는 무엇인가요?
- 표준웹 표준이나 언어 명세가 정한 동작
- 구현특정 기술이나 브라우저가 실제로 구현한 동작
- 측정명시한 환경에서 직접 실행해 관찰한 결과
- 해석앞선 근거에서 도출한 설계 판단
- 미확인아직 공식 근거나 재현 결과를 확인하지 못한 내용
30초 요약
JavaScript Interface(JSI)는 JavaScript 엔진과 React Native의 C++ 기반을 연결한다. JavaScript와 C++가 서로의 객체를 참조하고 함수를 직접 호출할 수 있게 해 과거 Bridge의 비동기 큐와 값 변환에 의존하던 경계를 바꿨다.
그러나 직접은 다음을 뜻하지 않는다.
- 계산 비용이 0이 된다.
- 호출이 자동으로 백그라운드 스레드로 이동한다.
- 입력 타입, 오류와 취소가 자동으로 안전해진다.
- JSI 자체가 카메라·저장소 같은 앱 기능이다.
JSI는 연결 기반이다. 새 렌더러인 Fabric과 새 네이티브 모듈 체계인 TurboModules가 그 기반을 사용하며, 실제 실행 위치와 앱 API 계약은 각각 따로 정한다.
이 글을 관통하는 상황: 직접 호출인데 버튼이 300ms 멈춘다
가상의 영수증 앱이 촬영한 이미지의 체크섬을 계산한다고 하자. 체크섬은 입력 데이터에서
일정한 규칙으로 만든 짧은 확인값이다. 코드의 imageBytes는 이미지 픽셀을 바이트 단위의 숫자로
담은 입력이다. 개발자는 과거 비동기 API를 다음 동기 함수로 바꾸고 “JSI 직접 호출이므로 응답도
빨라질 것”이라고 예상한다.
function handleVerifyPress() {
setStatus('검증 중')
const checksum = ReceiptImageHost.hashLargeBuffer(imageBytes)
setStatus(`완료: ${checksum}`)
}hashLargeBuffer는 설명을 위해 JavaScript에 노출한 가상 C++ 함수다. 이 글에서는 실제 네이티브
모듈이나 C++ 코드를 만들지 않는다.
기록을 보기 전에 어떤 증거를 찾아야 할지 먼저 예측한다.
- JavaScript에서 C++ 함수까지 연결됐는지는 어느 시점으로 확인할 수 있는가?
- 300ms 계산은 호출 함수가 돌아오기 전과 후 중 언제 끝날 것으로 예상하는가?
- 그동안 다음 JavaScript 버튼 처리는 실행될 것으로 예상하는가?
아래 fixture, 즉 미리 준비한 가상 증거 묶음은 같은 시간 기준으로 관찰 결과를 정리한다. React Native가 고정 형식으로 출력하는 로그가 아니다.
0ms JavaScript handleVerifyPress 시작
1ms C++ hashLargeBuffer 진입
301ms C++ hashLargeBuffer 계산 종료
302ms JavaScript handleVerifyPress 종료
303ms 다음 JavaScript onPress 처리기록은 연결 실패가 아니라 성공한 동기 호출이 실행 경로를 오래 점유한 상태를 보여 준다. Bridge의 직렬화 비용을 없애도 체크섬 계산 자체의 300ms는 사라지지 않는다.
JSI는 엔진과 C++ 애플리케이션 사이의 인터페이스다
JSI는 Hermes만의 앱 기능 이름도 아니다. JavaScript 런타임과 C++ 호스트 애플리케이션이 상호작용할 수 있게 하는 낮은 수준의 기반이다.
이 변화가 줄이는 것은 연결 과정의 제약과 비용이다. 호출한 함수 안에서 실제로 수행하는 이미지 계산, 파일 읽기나 압축 비용까지 없애는 것은 아니다.
JSI와 그 위를 사용하는 체계는 같지 않다
| 이름 | 이 글에서의 역할 | 자세히 다룰 글 |
|---|---|---|
| JSI | JavaScript 엔진과 C++ 객체·함수의 연결 기반 | 현재 4편 |
| Fabric | React 계산을 플랫폼 UI로 옮기는 렌더러 | 5편 |
| TurboModules | 플랫폼 기능을 JavaScript API로 노출하는 모듈 체계 | 6편 |
| Codegen | 선언한 타입에서 연결 코드를 생성하는 도구 | 7편 |
따라서 “JSI 호출이 실패했다”는 말만으로는 조사 범위가 너무 넓다.
함수를 찾지 못함 → 모듈 등록·생성된 연결 코드부터 확인
입력 타입이 플랫폼별로 다름 → 모듈 타입 계약과 구현을 확인
화면이 반영되지 않음 → Fabric·호스트 컴포넌트 경계를 확인
함수는 되지만 응답이 늦음 → 실행 위치와 실제 작업 시간을 확인직접은 무료나 백그라운드라는 뜻이 아니다
New Architecture는 동기 호출도 지원한다. 동기는 호출한 쪽이 반환값을 받을 때까지 같은 호출 흐름에서 기다린다는 뜻이다.
따라서 다음 등식은 성립하지 않는다.
JSI 직접 호출 = 계산 비용 없음
JSI 직접 호출 = 자동 백그라운드 실행
네이티브 C++ = JavaScript 응답과 무관관통 사례에서는 C++ 진입이 1ms에 확인됐으므로 연결 자체는 성공했다. 문제는 301ms까지 반환하지
않은 동기 계산이다. 다음 onPress가 303ms에야 처리된 기록도 같은 실행 경로가 기다렸다는 증거다.
관찰 기록에서 연결과 실행을 나눠 읽는다
실무에서는 로그 하나를 “JSI가 느리다”로 요약하지 않고 구간을 나눈다.
| 구간 | 관찰 질문 | 현재 기록의 답 |
|---|---|---|
| JavaScript → C++ 진입 | 함수 연결과 인자 전달이 성공했는가? | 1ms에 진입함 |
| C++ 함수 내부 | 실제 계산이 얼마나 걸렸는가? | 약 300ms |
| C++ → JavaScript 반환 | 동기 반환까지 호출자가 기다렸는가? | 302ms까지 기다림 |
| 다음 사용자 사건 | JavaScript가 그사이 다른 사건을 처리했는가? | 다음 onPress는 303ms |
이 가상 기록은 실제 성능 수치를 대신하지 않는다. 운영 구현에서는 release 빌드의 측정 도구로 각 구간을 확인해야 한다. 이 글의 기록이 증명하는 것은 “직접 연결이 성공해도 큰 동기 계산은 남는다”는 판단 구조다. 도구와 실제 기기 측정 범위는 29편에서 다룬다.
연결 가능성과 운영 계약을 분리한다
hashLargeBuffer를 운영 가능한 기능으로 만들려면 적어도 다음 질문에 답해야 한다.
- 큰 계산은 JavaScript나 UI 응답을 막지 않는 별도 실행 흐름에서 수행하는가?
- 결과가 나중에 도착한다면 완료와 오류를 Promise나 사건 중 어떤 방식으로 전달하는가?
- 화면이 사라지거나 새 이미지가 선택됐을 때 이전 작업을 취소하거나 결과를 무시할 수 있는가?
- 계산이 끝날 때까지
imageBytes의 메모리를 누가 소유하고 안전하게 유지하는가? - Android와 iOS가 같은 입력, 오류와 체크섬 규칙을 제공하는가?
교정 방향은 “JSI를 비동기로 바꾼다”가 아니다. JSI는 기반이므로, 실제 모듈 API가 큰 작업을 별도 실행 흐름으로 넘기고 완료를 나중에 전달하도록 설계한다. 반대로 아주 작은 값을 즉시 읽는 함수라면 동기 호출이 적절할 수 있다. 선택 기준은 이름이 아니라 측정한 작업 비용과 호출 계약이다.
예를 들어 모듈이 “호출을 받으면 큰 계산을 별도 작업 흐름에서 수행하고, 완료 또는 오류를 Promise로 전달한다”는 계약을 제공한다면 호출부는 다음 모양이 된다. 이 코드는 JSI가 아니라 그 위를 사용하는 가상 모듈 API의 교정 예다.
async function handleVerifyPress() {
setStatus('검증 중')
try {
const checksum = await ReceiptImageModule.hashLargeBufferAsync(imageBytes)
setStatus(`완료: ${checksum}`)
} catch {
setStatus('검증 실패')
}
}같은 300ms 계산을 별도 실행 흐름으로 보낸다는 계약을 가정하면, 교정 후에는 다음과 같은 증거를 기대한다. 이 기록도 실제 React Native의 고정 로그가 아니라 계약을 검증하기 위한 가상 기록이다.
0ms JavaScript handleVerifyPress 시작
1ms 네이티브 작업 접수, 별도 실행 흐름에서 계산 시작
2ms JavaScript는 Promise 완료를 기다리며 다음 작업을 처리할 수 있음
3ms 다음 JavaScript onPress 처리
301ms 네이티브 계산 종료
302ms Promise 완료, JavaScript 상태를 완료로 변경이 최소 교정의 성공 조건은 단순히 최종 체크섬이 같은 데서 끝나지 않는다. 다음 onPress가 계산
종료보다 먼저 처리되고 완료·실패 상태가 한 번만 도착해야 한다. 작업 취소와 이전 결과 무시는 이
코드에 아직 구현되지 않은 별도 통합 계약이다. 실제 구현에서는 그 계약까지 추가한 뒤 Android와
iOS 각각의 release 빌드에서 순서와 결과를 측정한다.
같은 상황을 다시 진단한다
문제 JSI 기반 동기 체크섬 호출 뒤 다음 버튼 처리가 300ms 늦음
잘못된 판단 직접 네이티브 호출이므로 계산은 자동으로 빠르고 백그라운드에서 실행됨
관찰 C++ 진입은 성공했지만 함수가 300ms 뒤 반환하고 다음 onPress도 그 뒤 실행됨
원인 연결이 아니라 큰 동기 계산이 호출 경로를 점유함
행동 작업 위치와 비동기 완료·오류·취소·메모리 소유 계약을 모듈 API에 명시
검증 다음 onPress가 계산 완료 전에 처리되고 완료·오류가 한 번만 도착하는지 release에서 측정풀 리퀘스트에서는 다음을 확인한다.
- JSI와 그 위의 Fabric·TurboModule·Codegen 책임을 섞지 않았는가?
직접,동기,백그라운드를 같은 뜻처럼 사용하지 않았는가?- 큰 네이티브 작업의 실제 실행 위치와 시간이 측정됐는가?
- 완료·오류·취소와 입력 데이터 수명 계약이 있는가?
- Android와 iOS의 API 결과를 각각 검증했는가?
기억할 문장은 짧다.
JSI는 연결 기반이다. 직접 연결은 계산 비용과 실행 계약을 대신하지 않는다.
다음 글에서는 이 기반을 사용하는 Fabric이 React의 계산을 Android와 iOS의 실제 화면에 어떻게 반영하는지 살펴본다.
Active recall
기억에서 꺼내 보기
답을 쓰지 않아도 됩니다. 먼저 머릿속으로 답한 뒤 펼쳐서 정답·이유·흔한 오해를 비교하세요.
01JSI가 카메라나 저장소 기능을 JavaScript에 제공하는 네이티브 모듈 이름일까?
정답
아니다. JSI는 JavaScript 엔진과 C++ 애플리케이션을 연결하는 기반이고, 네이티브 모듈은 그 기반을 사용해 앱 기능을 노출하는 별도 체계다.
관련 설명 다시 읽기왜 그런가
연결 기반과 그 위에 만든 제품 API를 구분해야 실패 원인과 책임을 올바르게 좁힐 수 있다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
02JSI로 직접 호출하는 동기 함수라면 큰 계산도 자동으로 백그라운드에서 실행될까?
정답
아니다. 직접 호출은 연결 방식을 설명할 뿐 실행 스레드를 선택하지 않는다. 구현이 별도 작업 흐름으로 넘기지 않으면 호출 경로를 오래 점유할 수 있다.
관련 설명 다시 읽기왜 그런가
통신 비용을 줄이는 일과 계산 비용을 다른 실행 흐름으로 옮기는 일은 별도 설계다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
03동기 JSI 함수의 추적 기록에서 C++ 계산이 300ms 동안 이어지고 그 뒤 JavaScript onPress가 실행됐다면 어느 경계를 먼저 고쳐야 할까?
정답
JSI 자체를 교체할 것이 아니라 함수 구현의 실행 위치와 비동기 완료 계약을 먼저 고쳐야 한다.
관련 설명 다시 읽기왜 그런가
기록은 연결 성공과 함께 동기 계산이 호출 경로를 300ms 점유했다는 사실을 보여 준다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
04JSI가 연결을 제공하면 입력 타입, 오류, 취소와 객체 수명도 자동으로 안전해질까?
정답
아니다. 앱에 노출할 타입 계약, 실행 위치, 완료·오류·취소, 객체 수명과 플랫폼 일치는 사용하는 모듈과 구현에서 따로 정해야 한다.
관련 설명 다시 읽기왜 그런가
낮은 수준의 연결 가능성과 운영 가능한 API 계약은 다른 책임이다.
선택한 상태와 다음 복습일은 이 브라우저에만 저장됩니다.
출처와 검증 범위
아래 날짜는 링크를 마지막으로 열어 본 날입니다. 문서 상단의 검증일은 글의 설명과 적용 범위를 다시 확인한 날입니다.
- Cross-Platform Architecture GlossaryReact Native · 공식 문서 · 확인 2026-08-09
- About the New ArchitectureReact Native · 공식 문서 · 확인 2026-08-09
- New Architecture is hereReact Native · 공식 문서 · 확인 2026-08-09
- Render, Commit, and MountReact Native · 공식 문서 · 확인 2026-08-09
- Threading ModelReact Native · 공식 문서 · 확인 2026-08-09
- Performance OverviewReact Native · 공식 문서 · 확인 2026-08-09
- Native ModulesReact Native · 공식 문서 · 확인 2026-08-09