이전에 휴리스틱 알고리즘 (reconciliation의 핵심 알고리즘)에 대해 글을 적으며 다음번 글은 Fiber에 대해 적어보아야지라고 다짐을 했었다. 매번 느끼는거지만 정말 알고리즘을 알수록 재미있고 더 잘하고 싶어지는 것 같다.
그래서 Fiber란 무엇인가? 앞서 블로그에서 적은 글 처럼 diffing 알고리즘은 성능을 완벽하게 개선하지 못한다고 판단한 페이스북은 판단했고, 그래서 나온 알고리즘이 React Fiber이다.
우선, 이 Fiber에 대해 설명하자면 VDOM에 대해서 먼저 설명해야한다. VDOM은 버츄얼 돔으로 가상 돔을 JS 객체로 만든 것이다. 그렇다면 이런 VDOM을 왜 만든것이냐고 물어본다면 수십번, 수백번의 업데이트가 일어날 때 성능 이슈는 불가피하다. 그래서 React에서는 가상 돔을 사용하여 이전 돔과 현재 돔을 비교하여 (이때 diffing 알고리즘이 사용된다) 바뀐 부분만 업데이트 해주는 것이다.
그렇다고 오해하면 안되는 것이 실제 DOM은 성능이 떨어지는 것은 아니다. 다만, 업데이트 할 부분이 적다면 그냥 DOM에서 업데이트 하는것이 훨씬 유리하다. 그러면 VDOM을 사용하는 이유는? 아무래도 업데이트 부분의 장점도 있고, 선언형이라는 특징과 JSX를 사용해 조금 더 가독성있고 편하게 작성할 수 있다는 장점이 있다.
(2022.01.09 추가)
Webkit에서 노드의 스타일 처리 과정을 attachment라고 부르고, attach라는 메서드를 사용해 스타일을 계산해 객체 형태로 반환한다. 이 작업은 동기적으로 이루어지고, 계산되는 과정에서 다른 요소들의 스타일 속성을 참조한다.
왜 DOM Fragment가 아니라 VDOM을 사용할까? 결국 저 Fragment도 단 한번만 변화를 발생시키는데 그럼 VDOM으로 해결하지 않아도 되는 건 아닐까?
DOM Fragment는 수동으로 하나하나 개발자가 변경시켜줘야하다보니 어떤 값이 바뀌었고 바뀌지 않았는지 자동으로 파악해주어야한다. 그러다보니 큰 규모에서는 사용할 수 없다 (변화를 어떻게 다 기억하고 변경시켜주겠는가) 반면, VDOM은 이런것들을 다 자동으로 해준다.
그리고 VDOM이 무조건 빠르다!는 잘못된 생각이다. 선언적이고 JSX를 사용할 수 있어 가독성이 좋고, 업데이트가 대규모일 경우 '충분히 빠르게' 앱을 유지보수를 가능하게 하기 때문에 VDOM을 사용한다.
위에서 설명한 것 처럼 가상 돔을 건들이다보니 이 리액트는 애니메이션이나 레이아웃 변경이 발생하여 리렌더링이 발생하는 경우 더 적합하게 사용할 수 있도록 하는 것이다.(반대로 말하자면 이 부분이 취약할 수 밖에 없다. 재귀적으로 이미 일을 처리하고있다 보니 다른 일들은 stop되어있다는 문제점이 있었다. 그리고 UI 변화가 한 번에 발생한다면 frame을 떨으뜨릴 수 있다.) 즉, 이전의 diffing 알고리즘을 보완하는 것이 목표이다.
즉, 콜 스택을 UI 렌더링하는데 최적화시키고자 리액트 Component에 최적화된 스택을 재구현했다. 이 방법의 장점은 지속적으로 프레임들을 메모리에 넣고 실행시킬 수 있다는 점이다. (이 점이 에러 처리와 동시성 특성에 가능성을 가지고 있다)
type
and key
child
and sibling
return
: fiber은 반드시 한 개의 작업을 수행하고 나면 최신 정보를 return 해야한다.
pendingProps
and memoizedProps
pendingProps
와 memoizedProps
가 동일할 때, 앞의 결과는 재사용될 수 있고 불필요한 일을 줄일 수 있다는 장점이 있다. pendingWorkPriority
:fiber에서는 업무의 중요도를 보여준다.
alternate
, output
alternate는 대체가능하다는 말인데 cloneFiber
이라는 함수에 의해 만들어진다. 새로운 객체를 항상 만들기보다는 만약 이미 존재하는 fiber이라면 새로 만드는 것이 아니라 기존에 존재하는 fiber을 재사용하여 할당량을 줄인다.
output은 leaf node에서만 만들어지고 이 결과물은 트리에 옮겨진다.
Fiber은 기존의 Reconciliation을 보완한 것이다. 특히 애니메이션 부분을 개선시키겠다는 목표를 가지고 재귀적 동작에서 단방향 링크드 리스트로 보완했다.
이런 글을 볼때마다 정말 이런 알고리즘으로 성능을 개선하는 것이 정말 좋다고 생각한다. 앞으로도 열심히 공부해서 나도 이런 부분을 수정해서 배포할 수 있는 개발자가 되고싶다.