-
jsrender 사용시 화면이 나오다 만 경우Front-End 2021. 3. 2. 14:37
QA팀에서 어느 한 페이지에 화면이 나오다 말았다는 이슈가 들어왔다.
처음에는 육안으로 언뜻 보았을때 UI의 한쪽면이 안나오고 있길래 직감적으로 jsrender라는 플러그인을 사용해서 발생한 문제 인줄 알고 한동안 템플릿을 뜯었다 고쳤다 해봤다.
그러나 템플릿 자체에는 별다른 문제가 없었다.
콘솔과 크롬의 자바스크립트 디버깅을 이용해 jsrender의 render()함수를 통해 렌더링 해온 데이터를 출력해보면서 깨달았다.
그런데 이상한점은 랜더링 해온 데이터를 jquery의 html() 함수에 삽입한 경우에 데이터가 온전히 다 출력되지 않고 잘려서 DOM tree가 형성 되었다는 점이다.
$("#content").html( $jstemplate.render(data));
이때부터 나의 삽질이 시작되었다.
jsrender에 사용할 데이터는 500kb가 넘는 데이터가 들어있었고 그 안에는 1000개의 row로 구성된 배열이 들어 있었다. 그러나 화면에는 400번대에서 출력이 끊겼기 때문에 순간적으로 jQuery의 html()함수에 문제가 있을것이라는 생각이 들었다. 그래서 구글에 jQuery html() 함수에 대해 찾아보고 대량의 html파일이 들어왔을때 버그가 있는지 살펴보았다.
jQuery 문서를 찾아봤을때는 html()함수가 DOM을 구성하는데 데이터양이 제한이 있다거나 완성되기까지 기다리게 하는 등의 별다른 옵션은 찾아볼 수 없었다. 그러나 스택오버플로우에서 다음과 같은 이슈를 찾아볼 수 있었다.
위의 상황은 html파일의 크기가 클때(필자가 40MB넘는 html파일을 사용) jQuery의 html()함수를 쓸 경우 속도가 지연된다는 내용이었다. 당시 글을 읽었을때는 나와 비슷한 문제에 직면했다고 생각했었다(지연과 데이터가 안나오는 문제는 엄연히 다른 문제였지만 당시엔 문제해결에 급급해 정신적으로 믿고 싶었던것 같았다 +추가로 500kb는 크롬의 2GB에 비해 너무 미미한 데이터양;)
사람들의 답변 내용은 이렇다.
"브라우저의 메모리와 CPU RAM 등 클라이언트의 환경적인 제한문제다."
나는 부끄럽지만 브라우저에 대한 개념이 없었고 심지어 DOM이 뭔지도 제대로 몰랐었다. 그래서 그냥 이 문제를 클라이언트의 환경문제라고 생각해버리고 메모리 제한에 걸리지 않게 렌더링할 데이터 양을 줄일 목적으로 웹의 디자인을 페이징 처리 또는 무한스크롤로 구현하여 문제를 처리하려고 했었다.
그런데 여전히 찜찜함이 남아있었다.
그 이유는 브라우저의 캐시를 늘려도 데이터는 화면에 오류는 그대로 출력되었고 메모리 문제라면 dom에 로드되지 않았어야 하는데 콘솔에 innerHTML을 출력해보았을때 정상적으로 출력되고 있었던 점이 이상했다.
내가 알기로는 innerHTML에 있는 데이터가 DOM에 로드된 데이터로 알고 있었는데(잘못 알고 있던 사실) 실제로 화면에 출력된 데이터와 크롬 개발자 도구 elements탭에서는 정상적으로 나오지 않고 있었다. 그때부터 내가 브라우저 렌더링 방식에 대해 뭔가 잘못 알고있는지 개념이 헷갈리기 시작했다.그렇다면 브라우저는 화면에 어떻게 렌더링 하는가?
브라우저라는 소프트웨어 프로그램은 먼저 브라우저 엔진으로 구성되어있다.
Firefox 용 브라우저 엔진은 Gecko라고하고 Chrome은 Blink라는 WebKit 기반의 브라우저 엔진으로 구성되어 있다.
이 브라우저 엔진은 외부 또는 로컬로 부터 수신받은 Byte 코드를 DOM (문서 개체 모델) 개체로 까지 변환(convert)하는 몇 단계의 작업을 진행한다.
Byte 코드는 먼저 html 구문들로 해석이 되고(.html파일의 문자 인코딩을 기반으로 수행됨 ex utf-8) html구문들을 파싱하는 작업이 이뤄진다. 즉, 정리하자면 다음과 같다.
Bytes -> Characters -> tokens -> node -> DOM
Bytes 0과 1로 이루어진 컴퓨터가 이해할 수 있는 언어 Characters html코드 ex) <html>...</html> <div>...</div> 등 Tokens html코드를 파싱하면서 작은 단위로 쪼갬 ex) <div> 태그와 그 안에 속성들 Node 서로 연관된 token들을 묶어 하나의 개체로 만듬 ex) <div>...</div> 마지막으로 노드들이 만들어지면 부모-자식 관계, 인접 형제 관계 등에 따라 DOM이라는 트리 데이터 구조로 연결된다.
DOM(Document Object Model)
텍스트 파일로 만들어져 있는 웹 문서(html)를 브라우저에 렌더링하려면 웹 문서를 브라우저가 이해할 수 있는 구조로 메모리에 올려야 한다. 브라우저의 렌더링 엔진은 웹 문서를 로드한 후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데 이를 DOM이라 한다.
즉, 쉽게 말해서 DOM은 우리가 흔히 사용하는 html태그들을 브라우저가 인식할 수 있도록 객체로 만들고 트리구조로 구성한 모델이다. 흔히들 이 구조를 DOM tree라고 부른다.
이 때 중요한 것은 html을 파싱하면서 dom을 구성하다가 script태그를 만나면 DOM 구성이 일시 중지되고 DOM 구성 프로세스는 스크립트 실행이 완료 될 때까지 기다린다. 따라서 script태그의 위치가 중요한 요소로 작용할 수 있다.
굉장히 기본적인 내용인데 이 점을 간과하고 있었다.
다시 문제로 돌아와서 자세히 살펴보니
jsrender에 들어가는 데이터 안에 script 태그가 있었다. 그렇기에 화면이 나오다 만 것이었다.
(또한, innerHTML은 dom에 로드된 데이터가 아닌 파싱되기 전의 Characters가 들어가있음)
이것을 깨닫는데 일주일이라는 시간을 소요했다.
만약 브라우저의 렌더링 과정과 dom에 대한 개념을 제대로 이해하고 있었다면 시간을 절약할 수 있었을텐데 아직 갈길이 멀다는 것을 인정하고 많이 반성하게 되는 계기가 되었다.
이 글에 삽질한 내용을 전부 담진 않았지만 크로스 사이트 스크립트같은 보안적인 이슈일 수도 있겠다 싶기도 하고 돔트리 대신 렌더트리에 문제가 있었나 싶기도 하였는데 기회가 된다면 그쪽도 시간내어 공부를 하는것이 좋겠다는 생각이 든다.
출처
blog.logrocket.com/how-browser-rendering-works-behind-the-scenes-6782b0e8fb10/
'Front-End' 카테고리의 다른 글
해커톤에서 사용할 수 있는 다양한 프론트엔드(react, next) 빌드 및 배포 방법 (0) 2024.06.29 Nextjs13을 활용한 간단한 심리테스트 만들기 (0) 2023.03.23 Storybook 도입할 수 있을까? (0) 2023.01.31 웹 접근성 지침 적용방법 (IR 기법) (0) 2022.02.17