2018년에 가시화된 리액트네이티브의 새로운 아키텍쳐가 2022년 3월에 발표되었다.
따라서 기존 아키텍처의 한계점을 알아본 후, 새롭게 바뀐 아키텍처 도입으로 인한 이점과 RN플랫폼과 Thread에 대해 알아보자.
기존 아키텍처의 한계점
기존 아키텍처는 js계층에서 네이티브 계층으로 전달해야 하는 모든 데이터를 'Bridge'를 이용해 직렬화하여 작동했다. 이에는 몇가지 한계가 존재했다.
1. 비동기: 한 계층이 'Bridge'로 데이터를 제출하고 다른 계층이 이를 처리하기를 비동기적으로 '대기'하였다.
2. 단일 스레드: js 단일 스레드에서 모든 계산이 수행되어야 한다.
3. 부가적인 오버헤드 발생: 한 계층이 다른 계층을 사용해야 할 때마다 일부 데이터를 json으로 직렬화, 역직렬화해야만 했다. json 은 가벼운 형식이지만 이 또한 비용과 시간이 들었다.
새로운 아키텍처
새로운 아키텍처는 'Bridge'라는 개념을 버리고 JavaScript Interface (JSI)라는 다른 통신 메커니즘이 도입되었다. JSI는 JavaScript 객체가 C++의 참조를 보유하거나 그 반대가 가능한 인터페이스이다.
따라서, C++ 객체는 javascript 세계의 javascript 객체에서 메서드를 실행하도록 요청 할 수 있다.
이는 'Bridge'와는 다른 이점을 제공하게 되었다.
1. 동기적 실행
2. 동시성 : Js에서 다른 스레드에서 실행되는 함수를 호출 할 수 있게 되었다.
3. 낮은 오버헤드: 더 이상 데이터를 직렬화/역직렬화 할 필요가 없어져 비용이 발생하지 않는다.
4. 코드 공유: C++ 를 도입함으로써, 모든 플랫폼 공통 코드를 추상화하고, 플랫폼 간에 쉽게 공유할 수 있게 되었다.
5. 타입 안전성 : Js가 C++ 객체에서 메서드를 호출하고 그 반대가 되도록 하기 위해, 코드가 자동으로 생성되는 계층이 추가되었다. 이 코드는 flow또는 Typescript를 통해 타입이 지정된 js 사양에서 시작하여 생성된다.
새로운 아키텍처의 세가지 주요 변화
- Turbo Modules
- Javascript에서 네이티브 모듈을 직접, 동기적으로 호출하는 방식을 도입했다. Javascript에서 직접 네이티브 모듈을 호출 할 수 있게 되면서, 호출 과정이 단순화되고, 시간도 단축되어 전반적인 성능이 향상되었다.
- Turbo Modules를 통해 가능해진 동기적 호출은 네이티브 코드와 Javascript 코드 간의 통신이 직접적이고 효율적이게 만들었다. 이는 개발 과정 간소화와 코드 가독성 향상에 큰 기여를 했다.
- Fabric
- React Native의 새로운 UI 렌더링 아키텍처이다. JavaScript에서 네이티브 코드를 직접, 동기적으로 호출할 수 있다. 이는 JavaScript Interface(JSI)를 통해 가능하게 되었다.
- Fabric은 터치 이벤트를 보다 정확하게 처리할 수 있도록 도와준다. JSI를 통한 직접적인 상호작용으로 인해 스크롤, 제스처 인식, 애니메이션 등의 터치 기반 인터랙션에 대한 반응성과 정확성이 향상되었다.
- Codegen
- Codegen은 JavaScript에서 정적 타이핑을 이용해 React Native의 새로운 아키텍처에 필요한 보일러플레이트 C++ 코드를 자동으로 생성하는 도구이다. Codegen은 JavaScript에서 정적 타이핑을 이용해 React Native의 새로운 아키텍처에 필요한 보일러플레이트 C++ 코드를 자동으로 생성하는 도구이다.
- Codegen은 이 유형 정보를 이용하여 네이티브 코드와 JavaScript 코드 사이의 인터페이스에 대한 C++ 코드를 생성한다. 이로 인해 개발자는 네이티브 코드와 JavaScript 코드 사이의 통신을 위한 코드를 수동으로 작성할 필요가 없어지므로, 개발 과정이 단순화되고 오류 발생 가능성이 줄어든다.
RN 플랫폼 파트
1. 네이티브 코드 / 모듈
- iOS의 경우 C 나 Swift, Android의 경우 자바나 코틀린으로 작성되어 있다.
2. JavaScipt VM
- 모든 자바스크립트 코드는 JS 버츄얼 머신(VM)을 통해 작동되며, iOS/Android simulator와 기기는 JavaScriptCore 엔진을 사용한다. JavaScriptCore는 WebKit을 위해 제작된 오픈소스로 사용하는 대표적인 브라우저는 Safari이다.
- iOS의 경우 iOS platform에서 제공하는 JavaScriptCore를 사용한다.
3. React Native Bridge (New Architecture 이전)
- RN bridge는 C++/Java 로 제작되어 네이티브와 자바스크립트 스레드 사이의 통신을 가능하게 해준다.
- 메시지 전달을 위한 커스텀 프로토콜이 사용된다.
- React Native는 Main Thread → JavaScript Thread → Shadow Thread → Native side의 일련의 실행과정으로 실행이 되는데 많은 수의 연산이 필요할 경우(예를들어 매우 빠른 속도로 큰 규모의 리스트를 스크롤 할 경우) Native Bridge에서의 traffic jam이 발생한다.
- 위와 같은 traffic jam을 피하기 위해 레이아웃을 미리 계산(pre calculating)하는 방법도 있다.
- pre calculating을 통해 애초에 bridge를 건너는 횟수를 최소화하는 것이다.
React Native의 Thread
- UI Thread (Main Thread)
- Android 혹은 iOS의 UI렌더링에 사용된다.
- Shaodw 스레드에서 계산된 레이아웃을 기반으로 UI를 그려준다.
- JavaScript Thread
- JavaScript 로직이 실행되는 Thread
- 각종 API호출, 터치 이벤트가 처리되는 등의 스레드가 있다.
- 네이티브 뷰에 대한 업데이트는 일괄 처리되며 JavaScript Thread의 각 이벤트 루프 끝에서 네이티브 측으로 전달되며 결국에는 UI Thread에서 실행된다.
- 좋은 성능을 유지하기 위해 JavaScript Thread는 프레임 렌더링 데드라인 전에 배치 업데이트를 UI Thread에 전달할 수 있어야 한다.
- iOS의 경우 초당 60프레임을 표시하며 새로운 프레임을 생성하기까지는 16.67ms가 소요된다.
- UI를 느리게 하지 않기 위해서는 JavaScript 이벤트 루프에서 UI 변경으로 이어지는 복잡한 처리를 16.67ms이내로 처리해야 한다.
- ScrollView혹은 navigatoriOS의 경우는 JavaScript Thread에서 실행되지 않고 UI Thread에서 100% 실행 되기 때문에 위의 제약조건에 해당하지 않는다.
- Native Modules Thread
- 애플리케이션의 성능을 높이기 위해 커스텀 네이티브 모듈에 스레드를 생성할 수도 있다. 예를 들어 애니메이션은 JS 스레드에서 작업 부하를 줄이기 위해 별도의 네이티브 스레드에 의해서 처리된다.
- Shadow Thread
- JavaScript 스레드에서는 네이티브에 직접적으로 통신할 수가 없어 브릿지를 통해 Shadow Thread 라는 곳에 전달한다.
- 브릿지로 전달받은 데이터를 통해 레이아웃을 계산해준다
- Render Thread
- Android L(5.0)에서만 React Native의 Render Thread가 UI를 그리는데 사용된다. Render Thread는 UI를 그리는데 필요한 OpenGL명령을 생성한다.
참조
https://velog.io/@koreanhole/React-Native%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C
'React Native' 카테고리의 다른 글
[React Native] Expo Push Notification - API Server (0) | 2024.09.20 |
---|---|
[React Native] Expo Push Notification (3) | 2024.09.20 |
[React Native] Expo prebuild (0) | 2023.12.11 |
[React Native] ios, android 폰트 설정 (2) | 2023.12.04 |
[React Native] Navigation 에서 주로 사용하는 개념 (0) | 2023.07.29 |
댓글