본문으로 건너뛰기

React Native 아키텍처 개요

무료2019-09-07#Tool#React Native Architecture#React Native架构#React Native线程模型#React Native threading model#React Native内部原理

설계, 스레드 모델 등의 측면에서 React Native의 기존 아키텍처를 소개합니다.

1. 아키텍처 설계

전체적으로 Native, JavaScript, 그리고 Bridge의 세 부분으로 나뉩니다.

[caption id="attachment_2013" align="alignnone" width="625"]React Native layers React Native layers[/caption]

Native는 UI 업데이트 및 상호 작용을 관리하고, JavaScript는 Native 기능을 호출하여 비즈니스 로직을 구현하며, Bridge는 이 둘 사이에서 메시지를 전달합니다. 즉:

최상위 계층은 JavaScriptCore가 제공하는 JavaScript 런타임 환경에서 실행되며 React와 유사한 지원을 제공합니다. Bridge 계층은 JavaScript와 Native 세계를 연결합니다. 구체적으로 Shadow Tree는 UI 효과와 상호 작용 기능을 정의하고, Native Modules는 Native 기능(예: 블루투스)을 제공하며, 이 둘은 JSON 메시지를 통해 서로 통신합니다.

Bridge 계층은 React Native 기술의 핵심이며, 설계상 다음과 같은 세 가지 특징을 가집니다.

  • 비동기(asynchronous): 동기적 통신에 의존하지 않습니다.

  • 직렬화 가능(serializable): 모든 UI 조작을 JSON으로 직렬화하고 다시 변환할 수 있음을 보장합니다.

  • 일괄 처리(batched): Native 호출을 대기열에 넣고 일괄적으로 처리합니다.

UI 조작을 일련의 명령어로 설명하고 JSON 형식의 메시지로 직렬화합니다.

Just as React DOM turns React state updates into imperative, mutative calls to DOM APIs like document.createElement(attrs) and .appendChild(), React Native was designed to return a single JSON message that lists mutations to perform, like [["createView", attrs], ["manageChildren", ...]].

상당히 유연하여 이러한 명령 기반 메커니즘을 통해 JS 코드를 다른 JS 엔진에서 실행할 수도 있습니다. 이것이 바로 Chrome debugging입니다.

Chrome debugging, which runs all the JavaScript code asynchronously over a WebSocket connection.

2. 스레드 모델

React Native에는 주로 세 개의 스레드가 있습니다.

  • UI Thread: Android/iOS(또는 다른 플랫폼) 애플리케이션의 메인 스레드입니다.

  • Shadow Thread: 레이아웃을 계산하고 UI 화면을 구성하는 스레드입니다.

  • JS Thread: React 등 JavaScript 코드가 실행되는 스레드입니다.

또한 Native Modules 스레드 그룹이 있으며, 서로 다른 Native Module은 서로 다른 스레드에서 실행될 수 있습니다 (자세한 내용은 Threading 참조).

[caption id="attachment_2014" align="alignnone" width="625"]React Native threading model React Native threading model[/caption]

스레드 간의 상호 작용 관계는 다음과 같습니다.

P.S. 그림의 queue는 GCD dispatch queue를 의미하며, 스레드라고 간단히 이해해도 무방합니다 (정확한 표현은 아니지만).

3. 시작 과정

시간 순서대로 보면, 앱이 시작될 때 React Native 런타임 환경(즉, Bridge)을 초기화하고, Bridge가 준비되면 JS 실행을 시작하며, 마지막으로 Native 렌더링을 시작합니다.

전체 시작 과정은 다음과 같습니다.

[caption id="attachment_2015" align="alignnone" width="625"]React Native App start up flow React Native App start up flow[/caption]

여기서 위쪽 부분은 Bridge를 초기화하는 과정입니다.

이는 4개의 단계로 나뉩니다 (모두 시작 시점에 수행됨).

  • JavaScript 코드 로드: 개발 모드에서는 네트워크에서 다운로드하고, 프로덕션 환경에서는 기기 저장소에서 읽어옵니다.

  • Native Modules 초기화: Native Module 등록 정보를 기반으로 모든 Native Module을 로드하고 인스턴스화합니다.

  • Native Module 정보 주입: Native Module 등록 정보를 가져와 JS Context에 전역 변수로 주입합니다.

  • JavaScript 엔진 초기화: 즉, JavaScriptCore를 초기화합니다.

Bridge가 구축된 후 JavaScript 코드가 실행을 시작하여 사용자 인터페이스를 렌더링하고 비즈니스 기능을 구현합니다.

4. 렌더링 메커니즘

[caption id="attachment_2016" align="alignnone" width="625"]React Native threads React Native threads[/caption]

JS 스레드는 뷰 정보(구조, 스타일, 속성 등)를 Shadow 스레드로 전달하여 레이아웃 계산을 위한 Shadow Tree를 생성합니다. Shadow 스레드가 레이아웃 계산을 마치면 전체 뷰 정보(너비, 높이, 위치 등 포함)를 메인 스레드로 전달하고, 메인 스레드는 이를 바탕으로 Native View를 생성합니다.

사용자 입력의 경우, 먼저 메인 스레드가 관련 정보를 이벤트 메시지로 패키징하여 Shadow 스레드로 전달합니다. 그런 다음 Shadow Tree에 구축된 매핑 관계에 따라 해당 요소의 지정된 이벤트를 생성하고, 마지막으로 이벤트를 JS 스레드로 전달하여 대응하는 JS 콜백 함수를 실행합니다. 즉:

[caption id="attachment_2017" align="alignnone" width="625"]React Native UI interaction React Native UI interaction[/caption]

이제 모든 것이 명확해졌습니다.

참고 자료

댓글

아직 댓글이 없습니다

댓글 작성