- It ensures that pages from different websites are always put into different processes.
- It also blocks the process from receiving certain types of sensitive data from other site
즉, Chrome's Site Isolation effectively makes it harder for untrusted websites to access or steal information from your accounts on other websites.
Cross-Origin Read Blocking(CORB)
Cross-Origin Read Blocking (CORB) is an algorithm that can identify and block dubious cross-origin resource loads in web browsers before they reach the web page.
For example, it will block a cross-origin text/html response requested from a <script> or <img> tag, replacing it with an empty response instead.
CORS doesn’t explicitly allow access to the resource
그리고 CORB는 위 조건을 만족한다면
renderer process가 a cross-origin data resource를 받아와 사용하는 것을 금지한다.
(a new security feature that prevents the contents ofbalance.json from ever entering the memory of the renderer process memory based on its MIME type.)
참고)
X-Content-Type-Options: nosniff는 Microsoft에서 제안하는 확장 헤더이며 웹서버가 보내는 MIME 형식 이외의 형식으로 해석을 확장하는 것을 제한하는 크로스사이트스크립트 방어법이다.
즉, nosniff 옵션이 켜있다면 브라우저는 이게 HTML, XML, JSON중 하나인것으로 Content-type 종류로 인하여 헷갈리지 않고 바로 확정 지을 수 있다.
(가끔 어떤 서버는 이미지에 대해 text/html로 잘못 분류하기도 한다. 이걸 방지 가능)
이점
CORB를 사용하면 다음과 같은 이점이 있다.
- Mark responses with the correct Content-Type header.
- out of sniffing by using the X-Content-Type-Options: nosniff header.
- 보안! (In browsers with Site Isolation, it can keep such data out of untrusted renderer processes entirely, helping even against side channel attacks like Spectre)
브라우저 관점에서 입력이란 모든 사용자의 제스처(이벤트)를 의미한다. 스크롤도 이벤트이고, 화면 터치, 마우스 포인터를 올리는거도 입력 이벤트이다.
화면 터치와 같은 사용자 제스처가 발생했을 때 가장 먼저 제스처를 수신하는 것은 브라우저 프로세스이다. 브라우저 프로세스는 제스처가 어디에서 발생했는지만 알고 있다. 탭 내부의 콘텐츠는 렌더러 프로세스가 처리해야 한다.
그래서 브라우저 프로세스는 이벤트 종류와 좌표값(x,y 등)만 렌더러 프로세스에 넘기게 된다.
렌더러 프로세스는 이벤트 대상과 이벤트 리스너를 실행해 이벤트를 적절히 처리한다.
스크롤의 예시로 렌더러 프로세스 내부동작을 알아보자.
스크롤할때 레스터화된 레이어를 컴포지터가 합성해 스크롤을 부드럽게 처리한다.
이벤트리스너가 없다면 컴포지터 쓰레드는 메인 쓰레드와 상관없이 스스로 합성해서 프레임을 만들어낼 수 있다.
그런데 이벤트가 달려있다면 다르게 동작하게 된다.
합성하는 쓰레드는 컴포지트 쓰레드이고,
이벤트를 실제로 처리하는 쓰레드는 JS를 동작시키는 메인 쓰레드이다.
어떻게 둘이 상호작용을 하게 될까?
고속 스크롤 불가 영역(non-fast scrollable region)
JS가 실행되는 작업은 메인 스레드의 영역이므로 이벤트 핸들러가 연결된 영역을 고속 스크롤 불가 영역(non-fast scrollable region)이라고 표시한다. 이 영역에서 이벤트가 발생하면 렌더러 프로세스는 우선 컴포지터 스레드에게 작업을 보내고, 컴포지트 스레드는 입력 이벤트를 메인 스레드로 보내야하는지 정보를 확인 후 넘겨준다.
만약 고속 스크롤 불가 영역이 아니라면 컴포지터 스레드는 메인 스레드를 기다리지 않고 새 프레임을 합성한다.
(컴포지터 스레드는 복사된 자신만의 레이어 트리를 가지고 있는다. - pending tree -> active tree?)
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()가 내부에서 실행이 안될꺼라는 약속이라는데
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를 사용하면 합쳐진 이벤트의 정보를 얻을 수 있다.
그리고 미디어 쿼리를 이용해 자신이 사용하는 미디어 타입에 걸맞는 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)
페이지를 그리는 방법
컴포지팅은 한 페이지의 부분들을 여러 레이어로 나누고 그 것들을 각각 레스터화하며 컴포지터 스레드에서 페이지를 합성하는 기술이다. 그리고 만약 스크롤이 발생하면, 레이어들이 이미 레스터되었기 때문에, 해야 할 것은 새로운 프레임을 합성하는 것이다.
에니메이션은 레이어들을 움직이는 동일한 방식으로 이뤄지고 새로운 프레임을 합성한다.
어떻게 웹 사이트가 여러 레이어로 나뉘는 지 개발자 도구의Layers panel에서 볼 수 있다.
참고) 레스터화와 벡터화
레스터화는 각 요소 이미지를 컴퓨터가 이해할 수 있는 비트맵으로 변환하고, 하나의 비트맵으로 합성하는 과정이다.
그리고 OS는 프로세스에게 메모리 한 조각을 주고 모든 상태 정보를 고유 메모리 공간에 저장할 수 있게 한다. 어플리케이션이 끝나면 프로세스도 사라지고 OS가 메모리를 해제한다.
(개인적 생각으로 여기서 말하는 메모리는 RAM 메모리를 뜻하는것으로 추론된다.)
프로세스간 통신 - Inter Process Communication (IPC)
그리고 프로세스는 다른 프로세스에게 별도의 작업을 수행하도록 요청 혹은 통신이 가능하다. 많은 어플리케이션이 이 방식을 채택하고 있어 워커 프로세스가 무응답 상태에 빠지더라도 어플리케이션의 다른 부분을 수행하고 있는 프로세스들을 종료할 필요 없이 해당 프로세스만 재시작할 수 있다.