불러오는 중입니다
실행 흐름이 하나뿐인데도 브라우저는 클릭, 타이머, 네트워크 응답을 함께 처리합니다. 그 사이에서 무엇을 먼저 실행할지 정하는 규칙을 따라갑니다.
자바스크립트의 비동기 동작을 이해하려면 먼저 자바스크립트가 왜 싱글 스레드로 동작하는지, 그리고 그 위에서 작업들이 어떤 순서로 처리되는지부터 짚고 넘어가야 합니다. 이 글에서는 그 출발점이 되는 이벤트 루프의 기본 동작을 정리합니다.
JS는 Single Thread에서 작동합니다. 즉 한 번에 하나의 작업만 동기 방식으로 처리할 수 있습니다.
동기(synchronous): 직렬 방식으로 작업을 처리하는 것. 요청이 시작하고 응답을 받은 후에야 다음 작업을 처리합니다.
비동기(Asynchronous): 작업이 끝나기를 기다리지 않고 다음 작업을 처리하는 것. 요청을 보낸 뒤 응답이 오기 전에도 다른 작업을 진행하고, 응답이 오면 그때 결과를 처리합니다.
비동기 방식에서는 사용자가 검색어를 입력해 검색을 위한 네트워크 요청이 발생한 순간에도 다른 작업을 처리할 수 있습니다.
리액트에서는 16 버전에 접어들면서 비동기식으로 작동하는 방법이 소개되었습니다.
과거에는 프로그램을 실행하는 단위가 Process뿐이었습니다.
Process
프로그램을 구동해 프로그램의 상태가 메모리 상에서 실행되는 작업 단위
현재는 하나의 프로그램에 여러 가지 작업이 필요해졌고, 더 작은 실행 단위인 thread가 등장했습니다. 하나의 process에는 여러 개의 thread를 만들 수 있고, thread끼리는 메모리를 공유하며 여러 작업을 동시에 수행할 수 있습니다.
자바스크립트는 기본적으로 싱글 스레드입니다.
비동기 동작을 이해하려면 Event Loop를 알아야 합니다.
Node.js와 마찬가지로 브라우저 측 자바스크립트 실행 흐름도 Event Loop에 기반을 둡니다. Event Loop를 잘 알고 있어야 아키텍처를 올바르게 설계할 수 있습니다.
자바스크립트 엔진은 다음 알고리즘으로 동작합니다.
자바스크립트 엔진은 대부분의 시간을 아무 일도 하지 않고 쉬다가, 스크립트나 핸들러, 이벤트가 활성화될 때만 돌아갑니다.
자바스크립트 엔진을 활성화하는 task는 다음과 같습니다.
<script src="...">가 로드될 때, 이 스크립트를 실행하는 것mousemove 이벤트와 이벤트 핸들러를 실행하는 것setTimeout에서 설정한 시간이 다 된 경우, 콜백 함수를 실행하는 것task는 하나의 집합을 이룹니다. 자바스크립트 엔진은 해당 task를 차례대로 처리하며 새로운 task가 추가될 때까지 기다립니다. task를 기다리는 동안 CPU 자원 소비는 0에 가까워지고 엔진은 잠들게 됩니다.
엔진이 바쁠 때 task가 추가되면 해당 task는 Macrotask queue에 추가됩니다.
참고로
task queue의 구조는queue가 아닌set입니다. 선택된 큐에서 실행 가능한 가장 오래된 task를 가져와야 하기 때문입니다. 무조건 먼저 들어온 첫 번째 항목을dequeue하는 것이 아니라, 실행 가능한 것들 중 가장 오래된 task를 차례대로 실행시킵니다.https://html.spec.whatwg.org/multipage/webappapis.html#definitions-3
(script를 처리하는 도중 mousemove 핸들러도 실행되고, setTimeout에서 설정한 시간이 지나 콜백이 들어온 경우의 상태를 그림으로 나타냈습니다.)
자바스크립트 엔진은 이들을 차례대로 처리합니다. 이때 알아야 할 두 가지가 있습니다.
이 두 번째 특성 때문에 무거운 task 하나가 화면 전체를 멈추게 할 수 있습니다. 다음 편에서는 이런 무거운 작업을 어떻게 쪼개서 화면을 살려두는지 살펴보겠습니다.
await는 비동기 코드를 위에서 아래로 읽히게 하지만, 실행 순서까지 그렇게 바꾸지는 않습니다. 출력 순서를 맞히는 문제로 시리즈를 마무리합니다.
여러 Promise를 한꺼번에 기다리다 하나가 실패해도 나머지 요청은 멈추지 않습니다. 결과를 버리는 것과 요청을 실제로 거두는 것은 다른 문제입니다.
then을 이어 붙이면 비동기 작업이 위에서 아래로 읽힙니다. 체인 중간 어디선가 터진 에러는 어디까지 흘러가서 잡힐까요?
배포가 끝나도 열려 있던 탭은 옛 코드로 계속 돌아갑니다. 그 탭에 새 빌드를 알리되, 알림이 틀려도 사용자에게 해가 없게 만든 과정을 정리했습니다.
데스크톱에서는 멀쩡한 인증 팝업이 iOS에서만 열리지 않았습니다. 원인은 금방 찾았지만, 고치는 일은 한 줄로 끝나지 않았습니다.
인증 분기를 서버로 옮겨도 본문은 여전히 비어 있었습니다. 화면 크기를 모르는 서버는 어느 레이아웃을 그려야 할까요?
인증 분기를 서버로 옮기자 모바일 e2e만 깨졌습니다. 클릭은 성공으로 기록됐는데, 화면에서는 아무 일도 일어나지 않았습니다.
브라우저에서는 멀쩡한 페이지가 크롤러에게는 스켈레톤뿐인 빈 문서였습니다. 서버 컴포넌트로 만든 페이지는 왜 서버에서 그려지지 않았을까요?
특정 요청도, 붐비는 시간대도 아닌데 502가 간헐적으로 떴고 다시 보내면 멀쩡했습니다. 무작위처럼 보이는 이 오류는 어디서 생긴 걸까요?