반응형

이 글은 사용자 입력(input)을 받았을 때 컴포지터가 어떻게 부드러운 상호작용을 하는지에 관한 글이다

(출처는 https://developers.google.com/web/updates/2018/09/inside-browser-part4)

 

Inside look at modern web browser (part 4)  |  Web  |  Google Developers

Input event handling with the compositor thread

developers.google.com

 

사용자 입력을 받았을때

 

브라우저 관점에서 입력이란 모든 사용자의 제스처(이벤트)를 의미한다. 스크롤도 이벤트이고, 화면 터치, 마우스 포인터를 올리는거도 입력 이벤트이다.

 

 

화면 터치와 같은 사용자 제스처가 발생했을 때 가장 먼저 제스처를 수신하는 것은 브라우저 프로세스이다. 브라우저 프로세스는 제스처가 어디에서 발생했는지만 알고 있다. 탭 내부의 콘텐츠는 렌더러 프로세스가 처리해야 한다. 

 

그래서 브라우저 프로세스는 이벤트 종류와 좌표값(x,y 등)만 렌더러 프로세스에 넘기게 된다.

렌더러 프로세스는 이벤트 대상과 이벤트 리스너를 실행해 이벤트를 적절히 처리한다.

 

스크롤의 예시로 렌더러 프로세스 내부동작을 알아보자.

 

그림 출처 : https://developers.google.com/web/updates/2018/09/inside-browser-part4#compositor_receives_input_events

 

스크롤할때 레스터화된 레이어를 컴포지터가 합성해 스크롤을 부드럽게 처리한다.

이벤트리스너가 없다면 컴포지터 쓰레드는 메인 쓰레드와 상관없이 스스로 합성해서 프레임을 만들어낼 수 있다.

 

그런데 이벤트가 달려있다면 다르게 동작하게 된다.

합성하는 쓰레드는 컴포지트 쓰레드이고, 

이벤트를 실제로 처리하는 쓰레드는 JS를 동작시키는 메인 쓰레드이다.

어떻게 둘이 상호작용을 하게 될까?

 

고속 스크롤 불가 영역(non-fast scrollable region)

 

JS가 실행되는 작업은 메인 스레드의 영역이므로 이벤트 핸들러가 연결된 영역을 고속 스크롤 불가 영역(non-fast scrollable region)이라고 표시한다. 이 영역에서 이벤트가 발생하면 렌더러 프로세스는 우선 컴포지터 스레드에게 작업을 보내고, 컴포지트 스레드는 입력 이벤트를 메인 스레드로 보내야하는지 정보를 확인 후 넘겨준다.

 

만약 고속 스크롤 불가 영역이 아니라면 컴포지터 스레드는 메인 스레드를 기다리지 않고 새 프레임을 합성한다.

(컴포지터 스레드는 복사된 자신만의 레이어 트리를 가지고 있는다. - pending tree -> active tree?)

 

그렇다면 여기서 한가지 의문점을 가지게 된다.

이벤트 위임을 설정할때는 어떻게 될까?

 

ex)

document.body.addEventListener('touchstart', event => {  
    if (event.target === wantedNode) {
        event.preventDefault();
    }
});

이벤트 위임을 document나 root 등 최상위에 선언했을때

이벤트위임을 최상위에 선언했을경우 다음 그림과 같이 페이지가 전부 고속 스크롤 불가 영역에 속하게 된다.

 

이런 문제를 방지하기 위해 passive : true 옵션을 전달하면 메인스레드에서 이벤트를 받지만, 컴포지터가 메인 스레드의 처리를 기다리지 않고 새 프레임을 만들어도 되는 힌트를 브라우저에 주는 옵션을 줄 수 있다.

ex)

document.body.addEventListener('touchstart', event => {  
    if (event.target === wantedNode) {
        event.preventDefault();
    }
}, {passive: true});

 

JS로 가로로만 스크롤을 제한하고 싶을때 

passive : true 옵션을 주면 부드럽게 스크롤이 된다는거까지는 알았다. 그런데 스크롤을 JS의 event.preventDefault() 함수로 제한한다면 쓰레드가 다르므로 event.preventDefault() 가 실행되기 전 이미 수직 스크롤이 실행될 수도 있다. 그래서 event.cancelable()를 사용하면 스크롤 시작 여부를 확인 가능하다.

document.body.addEventListener('pointermove', event => {
    if (event.cancelable) {
        event.preventDefault(); // block the native scroll
        /*
        *  do what you want the application to do here
        */
    }
}, {passive: true});

 

======

 

역주 : 모질라에 따르면 passive : true는  event.preventDefault()가 내부에서 실행이 안될꺼라는 약속이라는데

위 코드를 실제로 실행해보면 에러가 뜬다.

 

아래 링크 참고

https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener

위 코드를 복붙해서 실행했을때 나온 오류

https://stackoverflow.com/questions/37721782/what-are-passive-event-listeners

 

What are passive event listeners?

While working around to boost performance for progressive web apps, I came across a new feature Passive Event Listeners and I find it hard to understand the concept. What are Passive Event Listene...

stackoverflow.com

스텍오버플로우에 따르면

By marking a touch or wheel listener as passive, 
the developer is promising the handler won't call preventDefault to disable scrolling. 
This frees the browser up to respond to scrolling immediately without waiting for JavaScript, 
thus ensuring a reliably smooth scrolling experience for the user.

라는데 원글의 예시 코드는 이해를 돕기 위한 '예시'인지 좀 혼란스럽긴 하다.. 

일단 스택오버플로우와 원글의 공통점을 추론해보자면

passive : true를 설정하면 메인 쓰레드(JS)가 작동하지 않고 스크롤 이벤트때 컴포지트 쓰레드가 바로 동작하는 개념은 맞는듯 싶다.

 

======

 

(아무튼 계속 시작)

 

또는 아에 touch-action에서 아예 수직 스크롤 이벤트를 지워버릴수도 있다.

#area {
  touch-action: pan-x;
}

 

이벤트 대상 찾기

 

컴포지터 쓰레드가 메인 스레드로 보낼때 이벤트 대상을 찾는 hit test를 한다.

이벤트가 발생한 좌표에 무엇이 있는지 확인을 위해 paint recoards data를 이용한다.

(브라우저의 렌더링 단계에서 파싱->스타일->layout->paint->composite 에서 paint)

 

(아마 opcacity, transform등의 정보를 따로 담고 있는 property tree의 정보도 참고하기 위해서

paint tree를 참고하는거로 추론?)

 

메인 스레드 이벤트 전송 최소화

 

일반적으로 모니터는 1초당 60번 (60프레임) 화면을 갱신한다. 그리고 애니메이션도 화면 갱신 주기에 맞춰야

부드럽게 움직인다.

 

일반적으로 touchEvent는 초당 60~120회 전달하고, 마우스는 초당 100회정도 전달한다.

즉, 화면 갱신보다 이벤트 갱신 주기가 더 짧아서 이벤트가 뚝뚝 끊겨보이는 상황을 연출할 수도 있다.

 

너무 과도한 호출로 버벅거림을 유발하는 이벤트

 

그래서 메인 호출이 과다해지는것을 막기 위해서 Chrome은 자체적으로 연속적(coalesces continuous)인 이벤트(wheel , mousewheel , mousemove , pointermove , touchmove)는 다음번 requestAnimationFrame() 메서드 실행 직전까지 전송하지 않고 기다리게 된다.

 

keydown, keyup, mouseup, mousedown, touchstart, touchend와 같은 비연속적인(discrete) 이벤트는 즉시 전달된다.

 

한 프레임 안에서 합쳐진 이벤트 정보를 얻기 위해 getCoalescedEvent() 사용

드로잉 앱 같은 경우 프레임 사이 사이 경로가 누락되 선을 매끄럽게 그리지 못할 수도 있다. 이때 getCoalesecedEvents를 사용하면 합쳐진 이벤트의 정보를 얻을 수 있다.

 

 

 

 

reference 

 

https://d2.naver.com/helloworld/6204533

https://developers.google.com/web/updates/2018/09/inside-browser-part4

 

Inside look at modern web browser (part 4)  |  Web  |  Google Developers

Input event handling with the compositor thread

developers.google.com

 

반응형
반응형

수학적으로 멱등성이란

어떤 집합이 연산 A에 대해 닫혀있을때, 연산 A를 여러번 적용해도 달라지지 않는 성질을 뜻한다.

 

네트워크 HTTP 에서 멱등성이란

동일한 요청을 한 번 보내는 것과 여러 번 연속으로 보내는 것이 같은 효과를 지니고,

서버의 상태도 동일하게 남을 때, 해당 HTTP 메서드가 멱등성을 가졌다고 말한다.

 

다만 서버가 REST API를 잘 따랐다는 전제하에 멱등성 제약이 보장된다.

(ex : 서버가 get으로 CRUD 전체를 다 처리한다던가 restful하지 않게 구현되어 있다면 멱등성 보장 X)

멱등성이 성립하는 기준

 

멱등성은 요청의 효과를 보고 판단한다.

같은 행위를 여러번 반복하더라도 같은 효과를 가져야한다.

 

많이 쓰이는 http method중 POST를 제외한 GET, PUT, DELETE 가 멱등성이 보장되고,

그외 method로는 OPTIONS, HEAD 등이 있다.

 

예를 들어 PUT의 경우

 

PUT /user/4

 

라는 요청이 간다면 4번째 유저가 없다면 생성되고, 있다면 update 되는 형식으로 동작할것이다.

그런데 PUT 요청을 여러번 보내더라도 항상 4번 유저는 요청된 값과 똑같은 값으로 갱신하니

같은 상태일 것이다.

 

DELETE도 비슷한 방식으로 동작하고, GET, OPTIONS, HEAD 같은 경우는 조회(read) 동작만 하므로

항상 서버의 상태는 동일하다고 기대할 수 있다.

 

다만 PATCH(리소스의 일부만 수정)의 경우 멱등성이 보장이 되지 않는다.

예를 들어

 

PATCH users/1
{
    $increase: 'age',
    value: 1,
}

 

같이 increase하고 싶은 변수 이름과 값을 보낸다고 해보자.

그럼 PATCH를 보낼때마다 상태가 변경되니 멱등성을 기대할 수 없다고 볼 수 있다.

 

안전한 메소드

 

그럼 안전한 메소드란?

 

서버의 상태를 아예 변경시키지 않는 메소드를 말한다.

해당 메소드로는 GET, OPTIONS, HEAD 등 read 메소드들이 있다

 

 

https://velog.io/@dion/HTTP-%EB%A9%94%EC%86%8C%EB%93%9C%EC%9D%98-%EB%A9%B1%EB%93%B1%EC%84%B1-%EA%B7%B8%EA%B2%8C-%EB%AD%94%EB%8D%B0

 

HTTP 메소드의 멱등성? 그게 뭔데?

멱등성이 무엇인지 알고계신가요? 멱등성이란, 수학에서 사용하는 용어에서 유래한 것으로. 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 뜻합니다.이 멱등성은 왜 HTTP Method와 연

velog.io

https://oen-blog.tistory.com/211

 

[ RESTful API] PUT과 PATCH의 차이 - 멱동성을 보장하는 PUT, 멱등성을 보장하지 않는 PATCH

PUT 메소드는 반드시 멱등성을 보장하지만 PATCH 메소드는 멱등성을 보장하지 않을 수도 있다. 멱등성이란 멱등성이란 어떤 대상에 같은 연산을 여러번 적용해도 결과가 달라지지 않는 성질 이다.

oen-blog.tistory.com

 

https://developer.mozilla.org/ko/docs/Glossary/Idempotent

 

멱등성 - 용어 사전 | MDN

동일한 요청을 한 번 보내는 것과 여러 번 연속으로 보내는 것이 같은 효과를 지니고, 서버의 상태도 동일하게 남을 때, 해당 HTTP 메서드가 멱등성을 가졌다고 말합니다. 다른 말로는, 멱등성 메

developer.mozilla.org

 

반응형

'CS > 네트워크' 카테고리의 다른 글

AnyCast란?  (0) 2022.04.11
URL & URI & URN  (0) 2022.02.27
[TCP] 3-way handshake와 4-way handshake  (0) 2022.01.23
Pooling, Long Pooling, Streaming  (0) 2022.01.23
반응형

주의) 이글은 깁니다...

 

크롬에서 렌더링은 렌더러 프로세스가 담당한다.

이 글과 이전글은 GPU가 실제 클라이언트에서 어떻게 쓰이는지 원리를 알기 위해 찾아보았던 내용이다.

그 내용을 아래에 후술한다.

 

렌더러 프로세스에 관한 이전 글)

https://lodado.tistory.com/19

 

[운영체제] 크롬 웹 브라우저의 구조 (프로세스 & 쓰레드)

자바스크립트는 싱글 쓰레드이지만, 크롬 브라우저의 탭 하나하나는 각각 하나의 프로세스이고 멀티 쓰레드 환경이다. 이전에 썼던 이벤트 루프 관련 글에서 정확히 브라우저의 내부 구조가 어

lodado.tistory.com

 

www.google.com을 검색할때 크롬에서 일어나는일 

 

면접 단골 질문이긴 한데 네트워크 말고 크롬이 하는 일만 집중해서 간단히 살펴보자.

자세한 과정은 아래 링크를 추천한다.

브라우저마다 상세 구현은 다를 수 있기 때문에

'흐름' 을 파악하는 정도면 좋을 것 같다.

 

https://developers.google.com/web/updates/2018/09/inside-browser-part2?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 2)  |  Web  |  Google Developers

브라우저가 탐색 요청을 처리하는 방법을 학습하십시오.

developers.google.com

 

Brower Process 도식도

브라우저 프로세스는 주소 창, 뒤로 및 앞으로 이동 버튼을 포함한 어플리케이션의 "chrome" 부분을 제어한다.

또한 네트워크 요청 및 파일 액세스와 같은 웹 브라우저의 권한이 부여된 보이지 않는 부분을 제어한다.

 

브라우저 프로세스 내부를 보면

버튼이나 입력창을 그리는 UI 스레드,

인터넷에서 데이터를 수신하기 위해 통신 스택을 건드리는 네트워크 스레드,

파일 같은 것들에 접근하기 위한 스토리지 스레드

등을 가지고 있다. 

 

 

 

Browser Process가 내부 NetWork thread에 브라우저 탐색 과정을 수행하게 시키고, 작업이 완료되면 

Renderer Process에게 IPC를 통해 페이지 렌더를 요청한다.

이후 과정이 우리가 흔히 아는 브라우저의 렌더링 과정이다.

 

Renderer Process가 하는 일 

렌더러 프로세스는 브라우저 탭 안에서 일어나는 모든 일들을 담당한다.

렌더러 프로세스의 핵심 역할은 HTML, CSS 그리고 자바스크립트를 사용자가 인터렉션할 수 있는 웹 페이지로 만드는 것이다.

 

프로세스는 여러개의 쓰레드로 구성되어 있다.

 

Main Thread : 대부분의 코드를 처리한다. (파싱, 렌더 등)

Work Threads : 웹 워커 혹 서비스 워커를 사용할 경우 워커 스레드가 자바스크립트 코드 일부분을 처리한다.

Compositor & Raster Thread  : 렌더러 프로세스 내부에서 페이지를 효율적이며 매끄럽게 렌더하기 위해 실행된다.

compositor와 Raster thread의 역할은 후술한다.

 

브라우저의 렌더링 과정 

웹킷의 동작 과정

이것 또한 표준이 없어서... 세부 구현이 브라우저마다 다를 수 있지만 흐름 자체를 이해하자.

브라우저는 파싱  스타일  레이아웃  페인트  합성  렌더 등의 과정을 거친다. 그 후에 JS나 CSS를 통해 DOM이나 CSS에 변화가 생길 경우 reflow 혹은 repaint 등의 과정을 수행한다.

 

1) 파싱

 

HTML 파싱

 

브라우저가 HTML 을 파싱하고 읽어들이는 과정이다.

렌더러 프로세스가 탐색을 위한 커밋 메세지를 받고 HTML 데이터를 받기 시작할 때, 메인 스레드는 텍스트 문자열 (HTML)을 파싱하기 시작하고 이를 Document Object Model (DOM)으로 변환한다.

DOM은 페이지에 대한 브라우저의 내부 표현일 뿐만 아니라 웹 개발자가 자바스크립트를 통해 상호 작용할 수 있는 데이터 구조 및 API이다.

 

예측 파싱

HTML 문서에 <img> 혹은 <link>등이 있는 경우, 사전 로드 스케너는 HTML 파서에 의해 생성된 토큰들을 살짝 보고 브라우저 프로세스에 있는 네트워크 스레드에게 요청을 보낸다.

 

파싱 차단 리소스

 

파싱 과정에서 자바스크립트가 파싱을 중단시킬수도 있다.

<script> 태그를 만나면 HTML 문서를 파싱하는것을 멈추고 자바스크립트 코드를 로딩, 파싱, 실행한다.

이를 JavaScript는 파싱 차단 리소스(parser blocking resource)라고 부른다.

 

이를 방지하기 위해서는

 

  • <script>를 body 제일 아래에 놓는다 (가장 고전적인 방법)
  • 비동기로 데이터를 내려받고 다운로드가 완료되면 실행되는 async 태그를 사용한다.
  • 비동기로 데이터를 내려받고 파싱이 완료되면 실행되는 defer 태그를 사용한다. (가장 추천)
  • 리소스 우선순위화 - <link rel="preload"> 사용

가장 추천되는 방식은 head에 script + defer attribute이다.

asnyc, defer에 대해서는 아래 글 추천

 

https://guiyomi.tistory.com/101

 

Javascript - script 로딩 시 async vs defer

HTML 파일에서 외부 js 파일을 가져오는 방법은 다음과 같다. 그럼 여기서 궁금한 점이 발생한다. script 태그의 위치는 어디에 위치해야 할까? 보통 브라우저는 HTML 문서를 파싱할 때, 위에서부터

guiyomi.tistory.com

 

CSS 파싱

외부/내부의 스타일시트의 CSS를 해석해 CSSOM 트리를 구성한다.

속성을 주지 않아도 각 element들은 브라우저마다 고유의 css 속성을 가지며, 이것을 인위적으로 통일하거나

다 지우기 위해서 보통 개발할때 normalize.css나 reset.css를 사용한다.

 

렌더 차단 리소스(rendering-blocking-resource)

 

HTML, CSSOM이 완성 이전까지 브라우저는 렌더링을 멈추게 된다.

즉, css를 네트워크에서 빨리 받아오는게 중요하다.

<link rel="preload" as="script" href="super-important.js">
<link rel="preload" as="style" href="critical.css">

preload, preconnect, prefetch 등을 사용해 브라우저에게 우선순위를 알려줄 수 있다.

 

<link href="style.css"    rel="stylesheet">
<link href="style.css"    rel="stylesheet" media="all">
<link href="print.css"    rel="stylesheet" media="print">
<link href="portrait.css" rel="stylesheet" media="orientation:landscape">
<link href="other.css"    rel="stylesheet" media="min-width: 40em">

그리고 미디어 쿼리를 이용해 자신이 사용하는 미디어 타입에 걸맞는 css만 받아오고, 다른 기기의 css는 받아오지 않는 식으로 (용량을 줄여) 최적화 할 수 있다.

 

2) 스타일 

 

dom tree와 CSSOM tree가 생성되었다면 결합해서 Render Tree를 만든다.

렌더링 트리에는 페이지를 렌더링하는 데 필요한 노드만 포함된다.

 

그리고 어떤 렌더 객체는 DOM 노드에 대응하지만 트리의 동일한 위치에 있지 않다. float 처리된 요소 또는 position 속성 값이 absolute로 처리된 요소는 흐름에서 벗어나 트리의 다른 곳에 배치된 상태로 형상이 그려진다. 대신 자리 표시자가 원래 있어야 할 곳에 배치된다.

 

3) 레이아웃(재시작시 Reflow)

 

레이아웃은 요소들의 기하학적인 구조를 찾는 과정이다.

현재 viewport 기준으로 정확히 DOM이 어디있는지 위치, 크기를 계산한다.

 

만약 CSS나 돔의 layout과 관련된 요소(width, font-size 등)가 변경된다면 reflow 과정이 생길수도 있다.

 

추가적으로

 

display: none을 사용하면 렌더링 트리에서 요소가 완전히 제거된다.

visibility : hidden을 사용하면 레이아웃에서 공간을차지하지만 요소가 보이지 않는다.

 

그리고 레이아웃 트리를 순회하면서 속성 트리(property tree)를 만드는 작업이 페인트와 레이아웃 사이에 끼여있다.

속성 트리는 clip, transform, opacity등의 속성 정보만 가진 트리이다. 

최신 Chrome에서는 이런 속성만 별도로 관리하고 각 노드에서는 속성 트리의 노드를 참조하는 방식으로 변경되고 있다.

4) 페인트(재시작시 repaint)

레이아웃 트리를 따라가 페인트 기록을 생성한다.

 

배경 이미지, 텍스트 색상, 그림자등 실제 레이아웃의 수치를 변형시키지 않는 스타일의 변경이 일어나면

repaint만 발생한다.

일반적으로 reflow가 발생되면 repaint도 같이 발생한다.

(레이아웃 수치를 다시 계산해서 배치를 해야하기 때문에)

 

5. 합성(composite)

페이지를 그리는 방법

 

컴포지팅은 한 페이지의 부분들을 여러 레이어로 나누고 그 것들을 각각 레스터화하며 컴포지터 스레드에서 페이지를 합성하는 기술이다. 그리고 만약 스크롤이 발생하면, 레이어들이 이미 레스터되었기 때문에, 해야 할 것은 새로운 프레임을 합성하는 것이다.

 

 

https://developers.google.com/web/updates/2018/09/inside-browser-part3#what_is_compositing

에니메이션은 레이어들을 움직이는 동일한 방식으로 이뤄지고 새로운 프레임을 합성한다.

어떻게 웹 사이트가 여러 레이어로 나뉘는 지 개발자 도구의 Layers panel에서 볼 수 있다.

 

참고) 레스터화와 벡터화

 

레스터화는 각 요소 이미지를 컴퓨터가 이해할 수 있는 비트맵으로 변환하고, 하나의 비트맵으로 합성하는 과정이다.

https://m.blog.naver.com/reductionist101/221567932033

 

래스터, 벡터 차이

래스터(raster)와 벡터(vector)는 컴퓨터가 이미지를 저장하는 방식이며, 둘 사이에는 차이가 있다. 첫 번...

blog.naver.com

 

Layer에 대해서

 

메인 스레드는 레이아웃 트리를 순회하여 레이어 트리를 생성한다. (이 부분은 개발자 도구 성능 탭의 Update Layer Tree 참고)

 

모든 요소들에 대해 레이어를 지정할 수도 있다. 하지만 수많은 레이어를 합성하는 것은 웹페이지의 작은 부분을 매 프레임마다 새로 래스터화하는거보다 느릴 수 있다.

 

그래서 메인 쓰레드를 사용하지 않고 레스터와 컴포지트 하는 방식을 알아보자 (쉬운 말로 GPU를 써보자)

 

 

타일들을 레스터화(비트맵 생성) 시키고 GPU에 전송시키는 레스터 쓰레드들

레이어 트리가 생성되고 페인트 순서가 결정되고 나면, 메인 스레드는 컴포지터 스레드에게 정보를 커밋한다.

그러면 컴포지터 스레드가 각 레이어를 레스터라이즈(=레스터화)한다.

 

컴포지터 스레드는 레이어들을 여러 타일로 쪼개고 각 타일을 다수의 레스터 스레드에게 보낸다.

레스터 스레드들은 각 타일을 레스터화하고 그 것들을 GPU 메모리에 저장한다.

 

컴포지터 스레드는 서로 다른 레스터 스레드들에 대해 우선 순위를 정할 수 있어서 화면 안에 보이는 (혹은 가까이 있는) 것들이 먼저 레스터될 수 있다.

 

쿼드 군집으로 컴포지터 프레임을 생성해 GPU에게 IPC를 사용해 넘긴다.

 

타일들이 레스터되면, 컴포지터 스레드는 쿼드 군집(draw quads) 라 하는 타일 정보를 모아 컴포지터 프레임을 생성한다.

 

드로우 쿼드  메모리에서 타일의 위치 및 페이지 합성을 고려하여 타일을 그릴 페이지의 위치와 같은 정보를 포함합니다.
컴포지터 프레임 한 페이지의 프레임을 나타내는 쿼드 군집의 컬렉션입니다.

 

컴포지터 프레임은 IPC를 통해서 브라우저 프로세스에게 넘어간다. 

즉, 조각조각 내서 IPC로 넘긴다. 이해하면서 내 멘탈도 지금 조각조각 나고 있다.

 

 이 때, 다른 컴포지터 프레임이 브라우저 UI 변화에 따라 UI 스레드에 의해 혹은 확장 기능에 대한 다른 렌더러 프로세스들에 의해 추가될 수 있다. (GPU process는 하나니까.. 근데 이런 경우가 언제 있는지는 잘 모르겠다)

 

이러한 컴포지터 프레임들은 GPU에게 보내져 화면에 보여진다. 만약 스크롤 이벤트가 발생하면, 컴포지터 스레드는 GPU에게 보내질 다른 컴포지터 프레임을 생성한다.

 

이러한 방식의 장점은 메인 스레드의 개입 없이(reflow와 repaint 없이) 컴포지팅이 GPU에 의해 수행된다는 것이다.

 

 

현재 CSS의

  • opacity
  • translate
  • rotate
  • scale
  • will-change 

옵션이 GPU 가속을 지원한다.

그리고 전 글에도 적었지만, 무분별한 GPU 남용은 오히려 해가 된다.

보통은 잘 바뀌지 않는 값과 에니메이션을 레이어를 분리해 지정하는게 좋다. 

(The Animation Process From 1938)

이 영상에서는 배경은 그대로 두고 앞에서 움직여야 하는 전경만 별도의 셀로 만들어서 프레임을 촬영한다. 

-> 크기, 내용은 그대로고 이동(에니메이션)만 하는 element를 지정하는게 좋다

-> 작을수록 좋다

 

함께 읽어보면 좋을 글) 

 

https://docs.google.com/presentation/d/1QRchHprSPW4JVwAUVWmGmq3gmR8nLWrJmGYFzWHW9G4/edit#slide=id.g7b5233544_0274

 

Threaded GPU Rasterization

Threaded GPU Rasterization crbug.com/454500 State of GPU Rasterization (M-42)

docs.google.com

 

https://web.dev/why-speed-matters/

 

속도가 왜 중요합니까?

사용자 경험에서 속도는 중요한 역할을 합니다. 모바일 속도로 인한 지연은 실망스러울 뿐만 아니라 비즈니스 결과에도 부정적인 영향을 미칠 수 있습니다.

web.dev

 

https://web.dev/fast/

 

빠른 로드 시간

사이트 성능을 높이기 위한 기술.

web.dev

 

reference 

https://d2.naver.com/helloworld/5237120

https://d2.naver.com/helloworld/59361

https://junilhwang.github.io/TIL/Javascript/Design/Vanilla-JS-Virtual-DOM/#_1-%E1%84%87%E1%85%B3%E1%84%85%E1%85%A1%E1%84%8B%E1%85%AE%E1%84%8C%E1%85%A5-%E1%84%85%E1%85%A9%E1%84%83%E1%85%B5%E1%86%BC-%E1%84%80%E1%85%AA%E1%84%8C%E1%85%A5%E1%86%BC

 

Vanilla Javascript로 가상돔(VirtualDOM) 만들기 | 개발자 황준일

Vanilla Javascript로 가상돔(VirtualDOM) 만들기 본 포스트는 React와 Vue에서 사용되고 있는 가상돔(VirtualDOM) 직접 만들어보는 내용이다. 그리고 이 포스트를 읽기 전에 Vanilla Javascript로 웹 컴포넌트 만들

junilhwang.github.io

 

https://developers.google.com/web/updates/2018/09/inside-browser-part3?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 3)  |  Web  |  Google Developers

브라우저 렌더링 엔진의 내부 작동 방식

developers.google.com

https://velog.io/@itssweetrain/Reflow-%EC%99%80-Repaint

 

성능 최적화와 관련해서 : reflow 와 repaint

이렇게 렌더 트리 생성이 끝나면 배치가 시작된다. 레이아웃 단계는 트리를 생성하면서 계산된 노드와 스타일을 기기의 뷰포트에서 어떤 위치에서 어떻게 보이도록 하는지 결정하는 단계입니

velog.io

 

https://d2.naver.com/helloworld/2061385

 

 

https://medium.com/@cwdoh/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%81%AC%EB%A1%AC-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%9D%B8%EC%9E%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-4c9e4d715638

 

프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기

3년 전에 개인 블로그에 적었던 글이라 이미 보신 분들도 있으리라 생각됩니다만, 미디엄에서 이전의 기술관련 글들을 같이 관리할 겸 같이 포스팅하기로 하였습니다. :)

medium.com

 

반응형
반응형

자바스크립트는 싱글 쓰레드이지만, 크롬 브라우저의 탭 하나하나는 각각 하나의 프로세스이고 멀티 쓰레드 환경이다. 

이전에 썼던 이벤트 루프 관련 글에서 정확히 브라우저의 내부 구조가 어떻게 구성되었는지 궁금해서 찾아보았다. 

 

참고) 이전글

https://lodado.tistory.com/16

 

[이벤트루프] 자바스크립트에서 정확한 타이머 구현?

*잘못된 부분이 있으면 피드백 주시면 감사하겠습니다! 자바스크립트에서 타이머 이벤트를 쓸 수 있는 방법으로는 setTimeout, setInterval 두가지가 있다. 이 함수들이 어떻게 비동기를 지원할까? 자

lodado.tistory.com

컴퓨터 아키텍처 3개 레이어 - 브라우저가 돌아가는 환경

 

하단부의 Machine Hardware, 중앙부의 운영 체제, 상단부의 어플리케이션.

 

브라우저가 돌아가는 환경을 이해하기 위해서는 컴퓨터의 전반적인 구조를 이해할 필요가 있다.

 

Machine Hardware (스마트폰, 컴퓨터 등)

 

물리적으로 구현된 하드웨어 위에서 컴퓨터가 동작

실제 작업을 물리적으로 처리하는 공간이다.

최근에는 브라우저에서 단순 CPU를 넘어서서 고속 렌더링, 에니메이션을 처리하기 위해 추가적으로 GPU라는 개념이 등장했다.

 

CPU 

Central Processing Unit - CPU

 

CPU는 컴퓨터의 뇌라고 볼 수 있다.

다양한 작업을 실제적으로 처리하는 공간이다.

최근엔 싱글 CPU를 넘어서서 멀티 코어등 다양한 방식을 이용해 '병렬성'을 지원하려는 연구가 활발하다.

 

GPU

 

Graphics Processing Unit - GPU

최근 브라우저에서 GPU를 이용하려는 연구도 활발하다.

GPU는 공장이라고 비유할 수 있다.

CPU는 다양한 작업을 유연하게 처리하는데 특화되어 있다면

GPU는 연산을 수많은 코어에서 동시에 처리하는데 특화되어 있다.

GPU 가속 연산 덕분에 CPU 하나로는 오래 걸릴 연산을 금방 끝낼 수 있다.

 

GPU가 연산을 하기 위해서는 CPU가 GPU에 데이터를 전송해줘야 연산이 가능하다.

이것을 비유하자면 CPU는 배송 트럭이라고 생각하고, GPU는 공장이라고 비유해보면 좋을것 같다.

 

GPU Bottleneck - 병목현상

CPU가 배송(I/O, 효율적인 프로그래밍)를 빨리 해줘야 공장이 100% 효율로 가동 가능하다.

공장이 최신식(GPU의 성능이 매우 좋아도)이라도 CPU의 배송이 느리다면 제 효율을 낼 수 없다.

그리고 반대로 배송(CPU의 성능이 매우 좋아도)이 엄청 빨라도 공장의 효율이 좋지 않다면 제 효율을 낼 수 없다.

 

요약하자면 둘 다 중요하다.

안드로이드 같은 경우 웹앱을 사용할 경우

GPU 연산이 좋다고 모든 연산을 위임하다보면 위 GPU Bottleneck 현상 혹은 너무 많은 작업으로 오히려 CPU만 사용할때보다 느려질 수 있다.

 

그리고 하드웨어적인 한계가 있기 때문에 CPU, GPU의 성능을 아무리 올려도 언젠간 한계에 부딫치게 된다.

프론트엔드 엔지니어가 관여할 수 있는 부분은 '렌더링 최적화' 등 주어진 자원 내에 최대의 효율을 내는게 주 업무다.

 

Operating System (윈도우, 리눅스, 안드로이드 등)

 

소프트웨어적으로 구현된 운영체제 위에서 어플리케이션이 동작 

(운영체제는 하드웨어와 이용자 사이에서 쉽게 이용할 수 있도록 인터페이스 역할을 한다. 윈도우가 왜 이름이 '윈도우'인지 생각해보면 좋을듯!)

 

Application (브라우저 - 크롬, 오페라 등)

 

우리가 사용하는 브라우저 어플리케이션이다. 운영체제가 지시하는 메커니즘에 따라 CPU & GPU를 동작 시키게 요청한다. 

동작(프로그래밍)을 잘 시키냐에 따라 브라우저의 제 성능을 이끌어낼 수 있다. 

 

프로세스 & 쓰레드

 

그리고 브라우저 아키텍처를 이해하기 이전에 프로세스 & 쓰레드 구조를 이해할 필요가 있다. 

이 부분은 면접 단골질문이기도 하고 학교에서 많이 배우므로 간략하게 설명하고 넘어가겠다.

 

프로세스 

 

프로세스는 운영체제로부터 자원을 할당받은 작업의 단위이다.

즉, 어플리케이션 하나가 프로세스 하나가 될 수 있다.

 

참고) 프로그램에 대해

 

더보기

프로그램은 어떤 작업을 위해 실행 할 수 있는 파일을 말하며 메모리구조에서 code 영역에 있는 실제 물리적 파일을 뜻한다.

프로세스는 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램을 뜻하며 메모리에 올라와 실행되고 있는 프로그램의 인스턴스이다.

 

즉, 프로그램(passive) <-> 프로세스(active)관계라고 할 수 있다.

 

쓰레드 

 

쓰레드는 프로세스 내에서 운영체제로부터 할당받는 자원을 실행하는 단위이다.

프로세스 내부에서 여러개가 생길 수 있다.

 

그외 자세한 정보는 다음 링크 추천 

https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

 

[OS] 프로세스와 스레드의 차이 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

프로세스와 쓰레드 생성 과정

 

process 내부의 쓰레드들

 

어플리케이션이 실행되면 프로세스가 생성되고,

프로세스는 작업을 위해 쓰레드(들)을 생성 할 수 있다.

그리고 OS는 프로세스에게 메모리 한 조각을 주고 모든 상태 정보를 고유 메모리 공간에 저장할 수 있게 한다. 어플리케이션이 끝나면 프로세스도 사라지고 OS가 메모리를 해제한다.

 

(개인적 생각으로 여기서 말하는 메모리는 RAM 메모리를 뜻하는것으로 추론된다.)

프로세스간 통신 - Inter Process Communication (IPC)

 

IPC

그리고 프로세스는 다른 프로세스에게 별도의 작업을 수행하도록 요청 혹은 통신이 가능하다. 많은 어플리케이션이 이 방식을 채택하고 있어 워커 프로세스가 무응답 상태에 빠지더라도 어플리케이션의 다른 부분을 수행하고 있는 프로세스들을 종료할 필요 없이 해당 프로세스만 재시작할 수 있다.

 

IPC에 대한 정보는 다음 링크 추천

https://jwprogramming.tistory.com/54

 

IPC의 종류와 특징

IPC(Inter Process Communication) - 프로세스 간 통신에 대하여 종류와 특징들에 대하여 살펴보겠습니다. [리눅스 커널 구조] - 위 그림처럼 Process는 완전히 독립된 실행객체입니다. 서로 독립되어 있다

jwprogramming.tistory.com

 

브라우저 아키텍처

 

다른 여러 브라우저 구조들

중요한점은 브라우저를 구현하는 '표준'이 없기 때문에 브라우저(IE, 오페라, 웨일, 크롬 등등..)마다 내부 작동 방식이 다를 수 있다.

 

그래서 공통적인 흐름을 이해하는것이 중요하다. (ex : 프로세스 & 쓰레드 구조로 동작하는구나!)

이 글은 2018년 기준 크롬 브라우저를 기준으로 설명한다.

 

크롬의 멀티 프로세스 아키텍처 도식도

 

크롬은 멀티 프로세스 아키텍처를 이용한다.

*중요점 : 크롬은 여러개의 렌더러 프로세스를 가질 수 있다(보통 탭 하나당 하나).

 

각 중요한 프로세스의 설명은 다음과 같다.

프로세스 설명
브라우저 주소 창, 뒤로 및 앞으로 이동 버튼을 포함한 어플리케이션의 "chrome" 부분을 제어합니다.
또한 네트워크 요청 및 파일 액세스와 같은 웹 브라우저의 권한이 부여된 보이지 않는 부분을 제어합니다.
렌더러 웹사이트가 디스플레이 될 때 탭 안의 모든 것 담당.
플러그인 플래시와 같은 웹사이트가 사용하는 모든 플러그인 담당.
GPU 다른 프로세스와 분리된 GPU 작업을 제어합니다. GPU는 여러 앱의 요청을 제어하고 동일한 표면에 표시하기 때문에 다른 프로세스로 분리됩니다.

 

멀티 프로세스 아키텍처의 장점

 

그럼 왜 이런 멀티 프로세스 구조를 가질까?

 

개별 탭에서 실행되는 여러 프로세스의 도식도;

 

보통 탭 하나당 하나의 프로세스를 가진다. 

(추가적으로 사이트 격리 옵션이 켜지고 iframe이 내부에서 실행되면 하나의 개별 Renderer 프로세스를 또 가진다)

 

참고)

https://blog.chromium.org/2017/05/improving-extension-security-with-out.html

 

Improving extension security with out-of-process iframes

Security is critical to Chrome, and many features protect Chrome users as they browse the web. Google Safe Browsing warns users away from ...

blog.chromium.org

 

만약 크롬이 단일 프로세스 환경이고 renderer process가 다중 쓰레드 환경이라면 한 탭이 고장이 나게 되면 모든 탭에 영향을 끼치게 된다. (메모리 영역에서 stack을 제외한 heap, code, data 등 여러 영역을 공유하기 때문?) 

 

그런데 다중 프로세스 환경이라면 탭이 하나 고장한 경우 그냥 닫아버리고 다른 탭으로 이동하면 된다.

 

그외 장점으로는 보안 및 샌드박싱 (운영체제는 프로세스의 권한을 제한하는 기능을 제공)이 있다.

 

메모리 공간 절약

 

최종적인 크롬의 아키텍처

그런데 각 프로세스가 메모리 공간을 할당받아 사용하다보면 메모리 부족 현상이 일어날수도 있고 효율적이지 않다.

그래서 크롬이 고성능 장치에서 실행될 때에는 안정성을 위해 각 서비스를 별개의 프로세스로 분리하고, 자원이 부족한 장치에서는 서비스를 하나의 프로세스로 합쳐 메모리 점유를 낮추는 메커니즘이 들어가 있다.

 

즉, 크롬에서 최대 프로세스 개수에 제한을 두었다.

이 구조는 안드로이드에서도 구현되어 있어 유사한 프로세스를 합쳐 메모리 점유를 줄이는 방식을 실행한다.

 

기타 브라우저의 동작 방식

 

전반적으로 mutli process architecture를 따르는 듯하다.

 

IE8

 

 

 

크롬의 브라우징 프로세스와 렌더링 프로세스 두개를 심플하게 가지는거 같다.

One mainframe process

Zero or multiple tab processes

tab process의 경우 RAM 크기에 따라 자동으로 크기가 조절된다.

 

Firefox

 

Firefox의 경우엔 멀티 프로세스 아키텍처인것은 크롬과 동일하다. 다만 4개까지의 다중 프로세스를 허용하고 이후 

탭의 경우는 구글과 비슷하게 기존 프로세스 내부에서 메모리 영역을 공유한다.

 

Chrome using 1.77x more RAM than Firefox in 64-bit and 2.44x in 32-bit mode. (모질라의 주장에 따르면!)

 

모질라의 주장에 따르면 자기들이 메모리를 제일 적게 쓴다고 하는데

프로세스를 4개까지만 만드니까 당연한 내용이다 😂

 

 

같이 읽어보면 좋을 글)

https://levelup.gitconnected.com/how-web-browsers-use-processes-and-threads-9f8f8fa23371

 

How web browsers use Processes and Threads

A process can be described as an application’s executing program. A thread is the one that lives inside of process and executes any part…

levelup.gitconnected.com

 

https://medium.com/@cwdoh/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%81%AC%EB%A1%AC-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%84%B1%EB%8A%A5-%EC%9D%B8%EC%9E%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-4c9e4d715638

 

프론트엔드 개발자를 위한 크롬 렌더링 성능 인자 이해하기

3년 전에 개인 블로그에 적었던 글이라 이미 보신 분들도 있으리라 생각됩니다만, 미디엄에서 이전의 기술관련 글들을 같이 관리할 겸 같이 포스팅하기로 하였습니다. :)

medium.com

 

reference 

 

https://wvganjana.medium.com/how-web-browsers-use-process-threads-67e156abb3c5

 

How web browsers use Process & Threads

As we all know Chrome and Firefox both using multi-threading in architecture. But they support it in different ways.

wvganjana.medium.com

 

https://www.wepc.com/tips/cpu-gpu-bottleneck/

 

CPU and GPU Bottleneck: A Detailed Explanation

Have you ever experienced playing a game and you get sudden FPS drop from time to time? The next second, you’re dead.. If you try to observe, these sudden

www.wepc.com

 

https://developers.google.com/web/updates/2018/09/inside-browser-part1?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 1)  |  Web  |  Google Developers

브라우저에서 사용자 코드를 하이레벨 아키텍처부터 렌더링 파이프라인 세부 기능에 이르는 기능성 웹사이트로 전환하는 방법

developers.google.com

 

반응형
반응형

 

*잘못된 부분이 있으면 피드백 주시면 빠르게 수정하겠습니다!

 

ES5까지는 변수를 선언하는 방법은 var 밖에 없었습니다.

다만 변수의 유효범위를 설정하는데 어려움을 겪어서 ES6 이후 지역변수를 다루기 위해서 let, const가 등장하게 됩니다.

(var는 추가적으로 블록 스코프가 아닌 '함수 스코프' 개념을 따릅니다.)

자세한건 아래 링크를 참고하세요.

 

https://poiemaweb.com/js-scope

 

Scope | PoiemaWeb

스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙으로 자바스크립트는 이 규칙대로 식별자를 찾는다.

poiemaweb.com

 

 

호이스팅

 

JavaScript에서 코드를 실행하기 전 평가실행 과정을 거칩니다.​

그리고 변수는 위의 사진처럼 선언, 초기화, 할당이라는 3가지 단계를 거쳐 생성됩니다.

 

선언 단계(Declaration phase) : 변수를 실행 컨텍스트의 변수 객체에 등록하는 단계를 의미합니다. 이 변수 객체는 스코프가 참조하는 대상이 됩니다.

초기화 단계(Initialization phase) : 실행 컨텍스트에 존재 하는 변수 객체에 선언 단계의 변수를 위한 메모리를 만드는 단계 입니다. 이 단계에서 할당된 메모리에는 undefined로 초기화 됩니다.

할당 단계(Assignment phase) : 사용자가 undefined로 초기화된 메모리의 다른 값을 할당하는 단계 입니다.

모든 변수는 생성되면 위 3단계를 거쳐 생성됩니다.

그래서 자바스크립트가 실행되면 모든 변수들은 평가단계를 거치게 되는데, 호이스팅이란 모든 변수들을 끌어 모아서 각 유효범위(블록 {}안)에 최상단에 선언하는것을 말합니다.

var, let, const 모두 위 3단계를 거칩니다.

다만 var는 선언단계와 초기화 단계가 호이스팅 단계에서 동시에 실행됩니다.

그래서 아직 할당이 되지 않았는데 var로 생성된 변수를 부르게 되면 undefined를 되돌려 줍니다.

let,const는 선언은 되지만 초기화는 되지 않고, 할당이 되기 전까지 TDN(temporal dead zone)이라는 곳에 등록됩니다. 그래서 할당이 되지 않았는데 불러온다면 TDN 구간에 있는 변수들은 참조 에러(Reference Error)를 발생시키게 됩니다.

즉, 호이스팅은 모두 발생하지만 var와 let,const는 다루는 방법에 차이가 있게 되는것입니다.

다른 언어에서 흔히 쓰는 변수들은 구조적으로는 약간씩 다르겠지만 결론적으로 let, const와 동일하게 쓰인다고 이해하시면 편합니다.

참고로 함수 선언문은 위 3가지가 동시에 진행됩니다.

함수 선언식 예시

 

function func { ... }

 

그래서 어디서 선언하든 유효 범위 (스코프) 내에서는 사용할 수 있습니다.

함수 표현식 예시

함수 표현식은 변수처럼 동작하고 호이스팅 됩니다.

const func = () => { ... }
 

따라서 var, const, let중 뭘 썼는지에 따라 호이스팅되고 변수처럼 처리됩니다.

호이스팅을 하는 이유는 현재의 실행 컨텍스트의 지금 스코프 내부에 어떤 식별자들이 있는지 탐색하고, 렉시컬 환경에 저장(기록) 해놓기 위해서 입니다.

 

즉.. 자바스크립트의 모든 핵심 개념이 서로 연동되있다고 볼 수 있을꺼 같은데요

자세히 알아보시려면 JavaScript deep dive란 책을 읽어보시길 추천 드립니다!

 

 

그리고 이거에 대해서 재밌는 문제가 하나 있는데요,

클로저 개념과 연동되는 문제이니 한번 생각해 보시면 좋습니다.

 

for(var i =0; i <100; i+=1){
    setTimeout(function(){
        console.log(i);
    },i*1000);
}

해당 코드를 실행시키면 0, 1, 2, 3, 4가 출력되는게 아니라 100, 100, 100... 이 출력되게 되는데

원래 의도대로 고치려면 어떻게 해야할까요?

 

 

더보기
for(let i =0; i <100; i+=1){
    setTimeout(function(){
        console.log(i);
    },i*1000);
}

 

해설은 다음 글을 참고하세요.

 

https://www.bangseongbeom.com/javascript-var-let.html

 

자바스크립트 var, let 차이점

자바스크립트에서 변수를 선언할 때 사용하는 var, let, const의 차이와 스코프, 호이스팅에 대해 알아봅시다.

www.bangseongbeom.com

 

 

 

반응형
반응형

reflow, repaint를 피하거나 최소화

1. transition(CSS option)

성능 개선? 주제에 맞는 내용은 아니지만 부드러운 애니메이션을 구현하고 싶을때 참고

transform 속성은 reflow, repaint가 일어나지 않고 composite만 발생

(transform, opacity, cursor, orphans, perspective등도 Reflow, Repaint를 건너 뛴다,

원리는 브라우저에서 GPU를 사용해 하드웨어 가속하는 Update Layer Tree라는 내용 참고)

 

https://kyu9341.github.io/WEB/2021/02/03/WEB_GPU/

 

WEB - 하드웨어 가속 - kwon | kwon's Blog

하드웨어 가속 특정 작업을 CPU가 아닌 다른 특별한 장치를 통해 수행 속도를 높이는 것을 ‘하드웨어 가속(hardware accelerated)’이라 한다. 그래픽이나 사운드와 관련된 작업에 하드웨어 가속을 많

kyu9341.github.io

 

transition은 CSS 프로퍼티의 값이 변화할때 즉시 변화하는게 아니라

부드럽게 일정 시간에 걸쳐 일어나게 해준다

 

아래 예시 그림을 보자.

 

코드

<head>
  <style>
    .test-div {
      width: 100px;
      height: 100px;
      background: red;
    }
    .test-div:hover {
      border-radius: 50%;
      background: blue;
    }
  </style>
</head>

<body>
  <div class="test-div"></div>
</body>

 

네모에 마우스를 올리면 즉시 동그라미로 바뀐다.

그럼 transition 옵션을 부여한다면?

 

코드

<head>
  <style>
    .test-div2 {
      width: 100px;
      height: 100px;
      background: red;
      /* 트랜지션 효과: 모든 프로퍼티의 변화를 2초에 걸쳐 전환한다. */
      transition: all 2s;
    }
    .test-div2:hover {
      border-radius: 50%;
      background: blue;
    }
  </style>
</head>
<body>
  <div class="test-div2"></div>
</body>

transition은 자동으로 발동되지 않는다. :hover와 같은 가상 클래스 선택자(Pseudo-Classes) 또는 JavaScript의 부수적인 액션에 의해 발동한다. 

2. 클래스 변화에 따른 스타일 변화를 원할 경우, 최대한 DOM 구조 상 끝단에 위치한 노드에 추가

(부모가 바뀌면 자식에게도 영향을 준다?)

3. 애니메이션이 들어간 엘리먼트는 가급적 position: fixed 또는 position: absolute로 지정

애니메이션이 들어간 요소에 position: absolute 혹은 position: fixed 속성을 적용하면 다른 요소에는 영향을 끼치지 않으므로 페이지 전체가 아닌 해당 요소만 reflow가 발생

 

3. JS를 통해 스타일변화를 주어야 할 경우, 가급적 한번에 처리

var div = document.getElementsByTagName('div');
for (var i = 0; i < div.length; i++) {
    div[i].style.height = '80px';
    div[i].style.backgroundColor = '#00f';
    div[i].style.display = 'inline-block';
    div[i].style.overflow = 'hidden';
    div[i].style.fontSize = '40px';
    div[i].style.color = '#fff';
}

한번 style을 바꿀때마다 dom 조작이 일어나고 reflow-repaint가 일어난다.

즉, 순차적으로 dom 조작이 발생하는 식이다.

 

바꾸고 싶은 스타일을 담은 css class를 하나 만드는 식으로 구현하고, tag에 class를 붙이는 식으로 구현하자.

toggle이나 classList.add, classList.remove 등을 사용해서 js에서 class를 떼고 붙일 수 있다.

 

classList에 대한 내용)

https://hyunjungchoi.tistory.com/70

 

자바스크립트 classList를 써야하는 이유

~잠깐 사담~ 아직 공부한 지 얼마 안 됐지만, 자바스크립트는 너무 어렵다.ㅠㅠ 파이썬, 자바를 처음 배울때 보다 훨씬 어려움....ㅠㅠㅠㅠ 게다가 지금 챌린지 중인데, 잘하시는 분들 너무 많아

hyunjungchoi.tistory.com

 

혹은 cssText를 이용한다.

// Modal.jsuseEffect(() => {
    document.body.style.cssText = `position: fixed; top: -${window.scrollY}px`
  return () => {
    const scrollY = document.body.style.top
    document.body.style.cssText = `position: ""; top: "";`
    window.scrollTo(0, parseInt(scrollY || '0') * -1)
  }
}, [])

 

4. 인라인 스타일을 최대한 배제

3번 내용과 중복, reflow 비용을 줄이는 것 이외에 코드 가독성도 높일 수 있다.

 

5. 테이블 레이아웃을 피하는 것이 좋다.

테이블 값에 따라 넓이를 계산 -> 렌더링이 느려진다

만약 사용한다면 CSS 속성 table-layout:fixed를 사용하면 랜더링을 조금 더 빠르게 할 수 있다.

 

6. CSS 하위선택자는 필요한 만큼 정리

/* 잘못된 예 */
.reflow_box .reflow_list li .btn{
    display:block;
}
/* 올바른 예 */
.reflow_list .btn {
  display:block;
}

불필요한 선택자는 성능 저하

 

7. will-change 사용

 

미리 변화가 예상되는 요소를 브라우저에게 알려주는 기능이라는데 실제로 써보진 않았다.

불필요한곳에 남용하면 오히려 성능 저하를 일으킬 수 있는 요소

 

8. transform: translateY()등 이용

이동 애니메이션시 left, right 보다는 transform 이용(GPU 가속)

 

 

reference

 

https://poiemaweb.com/css3-transition

 

CSS3 Transition | PoiemaWeb

트랜지션(transition)은 CSS 프로퍼티 변경에 따른 표시의 변화를 부드럽게 하기 위해 애니메이션 속도를 조절한다. 즉, 프로퍼티 변경이 표시의 변화에 즉시 영향을 미치게 하는 대신 그 프로퍼티

poiemaweb.com

 

https://wit.nts-corp.com/2017/06/05/4571

 

CSS 애니메이션 성능 개선 방법(reflow 최소화, will-change 사용) | WIT블로그

CSS 애니메이션 성능 개선 방법(reflow 최소화, will-change 사용)

wit.nts-corp.com

 

https://medium.com/@bestseob93/%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%AA%A8%EB%8B%AC-react-modal-%EB%A7%8C%EB%93%A4%EA%B8%B0-bd003458e9d

 

효율적인 리액트 모달(react-modal) 만들기

안녕하세요.

medium.com

 

반응형

'Front-end > CSS' 카테고리의 다른 글

font-family 상속 시키기  (0) 2022.11.04
css 챌린지  (0) 2022.10.05
[CSS] box-sizing  (0) 2022.07.11
[CSS] Gap  (0) 2022.06.13
loading spinner  (2) 2022.02.13
반응형

*잘못된 부분이 있으면 피드백 주시면 감사하겠습니다!

 

자바스크립트에서 타이머 이벤트를 쓸 수 있는 방법으로는 setTimeout, setInterval 두가지가 있다.

 

이 함수들이 어떻게 비동기를 지원할까?

 

자바스크립트는 단일 쓰레드 기반의 언어이지만 이벤트 루프를 사용해서 동시성을 지원할 수 있다.

타이머를 실행시키면 Web API에서 타이머의 기한이 끝날때까지 대기하다가 테스크 큐로 들어오게 된다.

콜스택이 비었다면 테스크 큐에서 테스크를 가져와 실행한다.

 

이 말이 무엇인가를 다시 풀어써보기로 하자.

우선 Web API가 뭔지부터 알아야 할것 같다.

Web API 와 Javascript 런타임 

런타임이란 해당 프로그램 언어가 작성된 코드가 구동되는 환경을 뜻하고, 웹 브라우저나 Node.js 가 대표적 JS 런타임이다. 그리고 JS 이외에 다양한 기능을 제공하기 위해서 브라우저에서는 웹 API가 여러 함수(setTimeout등)을 지원하고, Node에서는 화면의 예시처럼 fs 등 함수를 지원하게 된다. 

 

브라우저 환경 구조 

자바스크립트 엔진

 

- Heap : 객체들은 힙 메모리에 할당된다. 크기가 동적으로 변하는 값들의 참조 값을 갖고 있다.
- Call Stack : 함수 호출 시, 실행 컨텍스트가 생성되며, 이러한 실행 컨텍스트들이 콜 스택을 구성한다.

 

Web API or Browser API


- 웹 브라우저에 구현된 API이다.
- DOM event, AJAX, Timer 등이 있다.

 

이벤트 루프

- 콜 스택이 비었다면, 태스크 큐에 있는 콜백 함수를 처리한다. (이후 자세히 설명)

 

태스크 큐

- 비동기 함수(setTimeout, setInterval 등)는 처리 전 이곳에서 대기하게 된다. 
- 이벤트 루프는 하나 이상의 태스크 큐를 갖는다.
- 태스크 큐는 태스크의 Set이다.
- 이벤트 루프가 큐의 첫 번째 태스크를 가져오는 것이 아니라, 태스크 큐에서 실행 가능한(runnable) 첫 번째 태스크를 가져오는 것이다. 태스크 중에서 가장 오래된 태스크를 가져온다.

 

(태스크 큐 관련해서 Microtask Queue, Animation Frames라는 세부적인 개념도 있는데 생략한다)

 

참고)

https://velog.io/@titu/JavaScript-Task-Queue%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%ED%81%90%EA%B0%80-%EB%8D%94-%EC%9E%88%EB%8B%A4%EA%B3%A0-MicroTask-Queue-Animation-Frames-Render-Queue

 

[JavaScript] Task Queue말고 다른 큐가 더 있다고? (MicroTask Queue, Animation Frames)

자바스크립트에서 비동기 함수가 동작하는 원리에 대해서 공부했다면, Task Queue에 대해 들어보았을 것이다. Task Queue는 Web API가 수행한 비동기 함수를 넘겨받아 Event Loop가 해당 함수를 Call Stack에

velog.io

 

싱글 쓰레드와 이벤트 루프

 

setTimeout같은 타이머는 JS 엔진이 아니라 외부에 구현되어 있다!

 

그리고, 자바스크립트가 단일 쓰레드 기반이라는 말이 정확히는 '자바스크립트 엔진'은 단일 호출 스택을 사용한다 라는 것이다.

 

위 그림같은 경우는 Node.js는 비동기 IO를 지원하기 위해 libuv 라이브러리를 사용하며, 이 libuv가 이벤트 루프를 제공한다. 브라우저에서는 Web API가 setTimeout 같은 함수를 지원하며, 타이머를 JS의 싱글 쓰레드가 아닌, 브라우저의 자체 쓰레드에서 세다가 자바스크립트의 테스크 큐에 넣어주게 된다. 

 

즉, 실제 자바스크립트가 구동되는 환경(브라우저, Node.js)는 여러개의 쓰레드를 사용하고, 이 다중 쓰레드 환경과 자바스크립트 엔진이 상호 연동하기 위해 내부적으로 이벤트 루프를 이용해 처리하게 된다.

 

(또 다른 예시로는 Node.js에서 I/O를 처리할때 자바스크립트의 싱글 쓰레드로만 동작하는게 아니고, 커널 쓰레드에서 처리하는것?이라 볼 수 있을것 같다?)

 

그럼 자바스크립트가 어떻게 비동기 함수를 처리하는지, 이벤트 루프를 어떻게 사용하는지 예시를 보자

 

function delay() {
    for (var i = 0; i < 100000; i++);
}
function foo() {
    delay();
    bar();
    console.log('foo!'); // (3)
}
function bar() {
    delay();
    console.log('bar!'); // (2)
}
function baz() {
    console.log('baz!'); // (4)
}

setTimeout(baz, 10); // (1)
foo();

 

위 코드를 작동시키면 setTimeout으로 타이머를 걸어놓은 baz가 정확히 10ms 이후에 실행되지 않는다.

 

그 이유는 자바스크립트가 비동기 함수를 지원하는 방식은 '이벤트 루프'를 사용해서 구현하고,

이벤트 루프는 '콜스텍에 현재 실행중인 task가 없는지'와 'task 큐에 태스크가 있는지'를 반복적으로 확인한다.

그리고 현재 실행중인 테스크가 없다면 이제서야 테스크 큐에 담겨있는 테스크를 꺼내와서 실행하게 되는것이다.

즉, 콜스택이 지금 바쁘다면 타이머 함수는 제 시간에 실행되지 않을 수 있다.

 

이를 하나의 함수가 실행이 완료되기 전에는 다른 함수가 실행될 수 없는 "Run to Completion" 라 부른다.

 

아래 코드 또한 좋은 예시이다.

let i = 0;

setTimeout(() => alert(i), 100); // ?

// 아래 반복문을 다 도는 데 100ms 이상의 시간이 걸린다고 가정합시다.
for(let j = 0; j < 100000000; j++) {
  i++;
}

실제 실행해보면 100000000이 나오게 된다.

 

(그나마?) 정확한 타이머를 구현하는 방법은?

 

(이 방법말고 다른 좋은 방법도 추천 받습니다!)

스택오버플로우 형님들의 경우는 아래의 코드와 비슷한 방식을 이용한다.

 

https://stackoverflow.com/questions/29971898/how-to-create-an-accurate-timer-in-javascript 

const interval = INTERVAL; // 1000ms
let time = Date.now() + interval;
let timerId = -1;

const exactlyTimeInterval = () => {
      const dt = Date.now() - time;
      time += interval;
		
      if (dt > interval) {
        // something really bad happened. Maybe the browser (tab) was inactive?
        // possibly special handling to avoid futile "catch up" run
        // 브라우저 말고 다른곳을 보고 있다면 브라우저의 타이머가 멈춰있고, 제대로 작동하지 않는다.
        // 그때 이 if문 안에 들어오게 된다
      }
      ...(생략)
      timerId = setTimeout(exactlyTimeInterval, Math.max(0, interval - dt));
    };
    
timerId = setTimeout(exactlyTimeInterval, interval);

 

setTimeout를 재귀적으로 실행하면 다음과 같이 function이 끝난 후 다음 계획을 실행한다.

setTimeout 예시

그래서 Date 객체의 now 값을 이용해서 실시간으로 다음 계획까지 걸리는 타이머를 보정받는다.

콜스택에 의해 지금 function의 실행이 늦었다면 다음 실행의 경우 늦은만큼 보정한다.

 

하지만 브라우저가 inactive(다른 화면을 보고있다던지)하게 되면 타이머는 정지되게 되고, 다시 브라우저가 활성화된다면 그때 황급히 카운트를 쭉 세게 된다.

 

100% 완벽한가? 까지는 아니지만 괜찮은 방법인거 같다.

 

함께 읽어보면 좋은 글)

 

운영체제의 프로세스 - 쓰레드 구조가 실제로 크롬 브라우저에서 어떻게 쓰이는지 

https://developers.google.com/web/updates/2018/09/inside-browser-part1?hl=ko 

 

모던 웹 브라우저 들여다보기 (파트 1)  |  Web  |  Google Developers

브라우저에서 사용자 코드를 하이레벨 아키텍처부터 렌더링 파이프라인 세부 기능에 이르는 기능성 웹사이트로 전환하는 방법

developers.google.com

 

reference 

 

https://meetup.toast.com/posts/89

 

자바스크립트와 이벤트 루프 : NHN Cloud Meetup

자바스크립트와 이벤트 루프

meetup.toast.com

 

https://velog.io/@yejineee/%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EC%99%80-%ED%83%9C%EC%8A%A4%ED%81%AC-%ED%81%90-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C-%ED%83%9C%EC%8A%A4%ED%81%AC-%EB%A7%A4%ED%81%AC%EB%A1%9C-%ED%83%9C%EC%8A%A4%ED%81%AC-g6f0joxx

 

이벤트 루프와 태스크 큐 (마이크로 태스크, 매크로 태스크)

자바스크립트는 싱글 스레드 기반의 언어이고, 자바스크립트 엔진은 하나의 호출 스택만을 사용한다. 이는 요청이 동기적으로 처리되어, 한 번에 한 가지 일만 처리할 수 있음을 의미한다. 만약

velog.io

 

https://ko.javascript.info/settimeout-setinterval

 

setTimeout과 setInterval을 이용한 호출 스케줄링

 

ko.javascript.info

https://stackoverflow.com/questions/29971898/how-to-create-an-accurate-timer-in-javascript

 

How to create an accurate timer in javascript?

I need to create a simple but accurate timer. This is my code: var seconds = 0; setInterval(function() { timer.innerHTML = seconds++; }, 1000); After exactly 3600 seconds, it prints about 3500 s...

stackoverflow.com

 

반응형

'Front-end > JavaScript' 카테고리의 다른 글

pnpm 도입기 (feat: 모노 레포)  (0) 2023.07.15
자바스크립트의 async/await에 대해서  (0) 2022.03.31
JS로 Single Page Application 구현  (0) 2022.03.12
Generator  (0) 2022.02.02
호이스팅과 var, let에 대하여  (0) 2022.01.29
반응형

폰 노이만 구조

현재와 같은 CPU, 메모리, 프로그램 구조를 갖는 범용 컴퓨터 구조의 확립

 

  • 산술 논리 장치와 프로세서 레지스터를 포함하는 처리 장치
  • 명령 레지스터와 프로그램 카운터를 포함하는 컨트롤 유닛
  • 데이터와 명령어를 저장하는 메모리
  • 외부 대용량 스토리지
  • 입출력 매커니즘

장점 

컴퓨터에 작업을 시키려고 할때 하드웨어적으로 재 배치를 할 필요가 없이 소프트웨어만 교체하면 되기 때문에

범용성(general-purpose)이 크게 향상된다.

따라서 현대의 컴퓨터는 거의 다 이 구조를 따르고 있다.

 

단점

메모리에서 데이터/코드(프로그램)을 가져올때 버스 하나로 한번에 하나만 가져오는 구조이기 때문에 폰 노이만 병목 현상이 일어날 수 있다.

이를 해결하기 위해 다양한 방법이 고안되었지만 폰 노이만 구조를 쓴다면 근본적 문제는 해결하진 못했다.

 

- 하버드 구조의 발명 

- 메모리 계층 구조(L1~L2 캐시, 메인 메모리, 하드디스크 구조)

- 다양한 방식 고안

ex) NUMA(메모리에 접근하는 시간이 메모리와 프로세서간의 상대적인 위치에 따라 달라진다.)

DMA(CPU가 직접 메모리 접근)

 

 

하버드 구조

하버드 아키텍처(Harvard architecture)는 명령용 버스와 데이터용 버스로 물리적으로 분할한 컴퓨터 아키텍처

명령용 버스와 데이터용 버스를 분할 -> 폰 노이반 병목 현상을 동시 접근으로 해결하려고 시도

 

단점 : cost(버스가 2배!)

 

현대에 이르러서는 CPU의 외부적으로는 폰 노이만 구조를, 내부적으로는 하버드 구조

 

reference

 

https://velog.io/@ckstn0777/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0

반응형

'CS > 컴퓨터구조' 카테고리의 다른 글

[컴퓨터 구조] cache, Write Through과 Write Back  (0) 2022.01.23
반응형

 

test 종류에 관한 이야기는 간략히 

 

https://lodado.tistory.com/category/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%EA%B3%B5%ED%95%99

 

'소프트웨어공학' 카테고리의 글 목록

https://github.com/lodado 이전 블로그 https://blog.naver.com/ycp998

lodado.tistory.com

에 적었다.

 

테스트가 좋다는건 많은 사람들이 알지만 제대로 된 테스트 케이스를 작성하는건 어려운것 같다.

 

TDD(Test Driven Development)란?

 

테스트가 개발을 이끌어 나간다.

기본 개발 방식은 요구사항 분석 -> 구현 -> 테스트라면 

TDD는 요구사항 분석 -> 테스트 -> 구현

 

그렇다면 TDD는 어떤 상황에서 해야할까?

처음해보는 프로그램 주제
나에 대한 불확실성이 높은 경우
고객의 요구조건이 바뀔 수 있는 프로젝트
외부적인 불확실성이 높은 경우
개발하는 중에 코드를 많이 바꿔야 된다고 생각하는 경우
내가 개발하고 나서 이 코드를 누가 유지보수할지 모르는 경우
즉, 불확실성이 높을 때 TDD를 하면 된다.

불확실성이 높다 -> 피드백 & 협력이 중요한 경우 

 

TDD 법칙

 

1. 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.

2. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.

3. 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

중요한것은 지저분한 테스트코드는 안하느니만 못하다는 것이다.

중요도로 따지면 기능 === 테스트 코드이다.

 

좋은 테스트 코드는 유연성, 유지보수성, 재사용성을 제공한다. 

즉, 테스트 코드가 좋으면 변경이 쉬워진다.

리펙토링에 거부감이 없어진다.

 

 

깨끗한 테스트 코드란?

 

가독성이 좋은 코드

명료성, 단순성, 풍부한 표현력 (중복성 제거)

 

최소의 표현으로 많은것을 나타냄

 

BUILD-OPERATE-CHECK 패턴을 추천

 

1. BUILD - 테스트 자료

2. OPERATE - 테스트 조작

3. CHECK - 조작 결과 체크(boolean식으로 체크하는게 좋음)

 

도메인(DSL)에 특화된 테스트 언어

API 위에다 함수, 유틸리티 구현 후 사용(경계-분리 엄청 좋아하시는거 같다)

테스트 당사자와 독자를 도와주는 테스트 언어

 

이중 표준

제한된 자원, 환경적 문제로 인해서

테스트 코드가 기능 코드랑 똑같은 환경, 컨벤션일 필요는 없다.

(mocking 관련?)

 

테스트당 개념 하나

 

테스트당 assert 하나라는 개념도 있다.

그것도 나쁘지는 않지만 저자는 기능 '하나'당 테스트 '하나' 추천

 

F.I.R.S.T 개념

 

Fast

테스트는 빠르게

(tmi로 cypress보다는 jest가 당연히 빠르고, 느리면 테스트를 주저하게됨)

 

Independent

각 테스트는 서로 의존적이지 않다.

독립된 환경설정

이유 : 독립되야 어디서 진짜 문제가 생겼는지 알기 쉽다 

 

Repeatable

어느 환경에서도 반복 가능, 동일한 결과

 

Self-Validating

bool 값으로 테스트 결과를 내야한다.

테스트를 파헤치지 않아도 결과를 알 수 있어야 한다.


Timely

테스트를 적시에 작성

단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현

 

결론

 

사실 '테스트' 라는 주제 하나만으로도 책 한권을 쓸 정도로 어려운 부분이다.

테스트 코드는 실제 코드만큼 중요하다

 

개인적 경험으로는 프로젝트때 테스트 코드를 한번 도입해보려고 시도했는데 

무작정 도입하고 보니 '깨끗하지 않은 테스트 코드'의 표본이 된거 같아서

이 글에서 말한 없느니만 못한 테스트가 된거 같기도 하다 😂

 

그래서 요즘 괜찮은 테스트를 짜기 위해 이론적으로 공부중이다.

 

테스트는 개인적으로 팀원간의 '공유 작업 파트'를 변경시 문제점을 빨리 캐치하고

커뮤니케이션 비용을 줄이는 측면에서 큰 도움이 된다고 생각되고,

또한 리펙토링의 거부감을 줄이는데 이점이 있다고 생각된다.

 

그밖의 tmi)

 

tistory에서 글자 색깔을 바꿀 수 있는걸 배웠다!

 

reference 

 

https://gmlwjd9405.github.io/2018/06/03/agile-tdd.html

 

[Agile] TDD(테스트 주도 개발)란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

반응형

'독서 > cleancode' 카테고리의 다른 글

cleancode - class  (0) 2022.02.26
clean code - 경계  (0) 2022.01.24
cleancode - 오류처리  (0) 2022.01.22
cleancode - 객체와 자료구조  (0) 2022.01.21
clean code - 주석 & 형식 맞추기  (0) 2022.01.20
반응형

 

 

 

테스트의 종류

Unit Test

테스트할 수 있는 가장 작은 단위(함수)로 기능을 쪼개서 테스트하는 방식

만약 문제가 일어난다면 어디서 일어나는지 가장 효과적으로 알 수 있다.

가장 좋은 방식이라 생각되는 테스트

 

도구) jest, mocha 등 사용

 

보통 jest의 경우는 프론트는 프론트만, 백엔드는 백엔드의 기능만 테스트하고 다른 부분은 mocking해서 

정상적으로 동작한다고 가정하고 해당 'Unit'만 테스트하는 방식이다.

 

-> 기능 테스트 위주로 하는거 추천?

 

Intergration Test

 

말 그대로 코드들을 '통합' 해서 문제가 없는지 확인하는 테스트

보통은 협업할때 내 코드와 팀원의 코드가 결합되도 문제가 없는지 확인하는 테스트이다.

커뮤니케이션적인 측면이 많이 필요한 테스트라 생각이 든다

 

도구) jest, cypress 등 사용

 

E2E(End-To-End) test

유저의 입장에서 내가 만든 프로그램이 의도대로 제대로 작동하는지 확인하는 테스트 

front, backend 전부 하나로 묶어서 테스트하고 실제 배포전에 문제를 발견하기 가장 쉬운 방법이지만

'어디서' 문제가 발견되는지는 까다로울 수 있다. (front인지 backend인지, 기능 여러개를 묶었다면 어디서 오류가 발생된건지 E2E test만으로는 발견하기 어려울 수 있음)

 

따라서 E2E test 만 하는것보다는 Unit test와 병행해서 하는것을 추천한다.

 

도구) 셀레니움, cypress 등 사용

 

-> UI 테스트는 E2E로 하는거 추천?

 

좋은 테스트의 비율?

 

구글 컨퍼런스에 따르면, 

Google often suggests a 70/20/10 split: 70% unit tests, 20% integration tests, and 10% end-to-end tests. 

라고 한다.

 

그외 팁으로는 

  • 기존의 레거시 코드는 E2E 테스트로 커버하라.
  • 새로 개발하거나 변경하는 부분을 대상으로 우선적으로 단위 테스트를 시작하라.

E2E 테스트 또한 기능이 복잡하거나 중요한 기능부터 커버하기 시작하면 효율적으로 단위테스트 적용이 가능할 것이다.

 

TEST의 장점

- 리펙토링시 test가 안정성을 담보하므로 거침없이 리펙토링을 할 수 있다.

- 코드 변경으로 어떤 부분이 영향이 있는지 빨리 파악 가능하다

- 테스트 자동화시(CI) 실수를 빨리 캐치하고 커뮤니케이션 비용을 줄일 수 있다.

- 버그 수정에 드는 시간을 줄일 수 있다

- test를 짜는데 초반엔 시간이 많이 들어도 장기적으로 보면 시간을 절약할 수 있다.

TEST의 단점

살충제 패러독스 

 

동일한 테스트 케이스를 사용하여 반복적으로 테스트를 수행하면 새로운 버그를 찾지 못한다.

소프트웨어는 복잡계이고, 테스트를 다 통과했다고 완벽한 소프트웨어는 아니다.

내가 예상치 못한 부분에 버그가 숨겨져 있을 수 있다.

 

- 러닝 커브

- 팀이 테스트에 대해 미적지근한 반응이라면 이도저도 안될수도 있음

 

같이 보면 좋을 동영상)

 

https://www.youtube.com/watch?v=jdlBu2vFv58 

 

reference 

 

https://codeahoy.com/2016/07/05/unit-integration-and-end-to-end-tests-finding-the-right-balance/

 

Unit, Integration and End-To-End Tests - Finding the Right Balance

Explore the difference between unit, integration and end-to-end tests and how to choose between them.

codeahoy.com

 

https://www.popit.kr/unit-test-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0-1%ED%8E%B8/

 

Unit Test (단위 테스트) 도입하기 - 1편 | Popit

원문 블로그 주소 : https://gregor77.github.io/2019/08/16/about-unit-test/ 관련글 : https://www.popit.kr/unit-test-단위-테스트-도입하기-2편/ 지금 부서의 역할이 사내에서 제품을 가지고 있는 팀들과 협업을 하면서

www.popit.kr

 

반응형

+ Recent posts