# Chapter15. 타임라인 격리하기
# 1. 타임라인 다이어그램 기본 규칙
- 기본 규칙
- 두 액션이 순서대로 나타나면 같은 타임라인에 넣는다.
- 두 액션이 동시에 실행되거나 순서를 예상할 수 없다면 분리된 타임라인에 넣는다.
- 요약
- 액션은 순서대로 실행되거나 동시에 실행된다.
- 순서대로 실행되는 액션은 같은 타임라인에서 하나가 끝나면 다른 하나가 실행된다.
- 동시에 실행되는 액션은 여러 타임라인에서 나란히 실행된다.
- 놓치기 쉬운 액션 순서에 관한 두 가지 사실
++
,+=
는 사실 세 단계이다.- 읽기(액션), 더하기(계산), 쓰기(액션)으로 분리된다.
- 인자는 함수를 부르기 전에 실행한다.
- 타임라인 다이어그램 그리는 단계
- 액션을 확인한다.
- 순서대로 실행되거나 동시에 실행되는 액션을 그린다.
- 플랫폼에 특화된 지식을 사용해 다이어그램을 단순하게 만든다.
# 2. 서로 다른 언어, 서로 다른 스레드 모델
- 단일 스레드, 동기
- 기본적으로 멀티스레드를 지원하지 않는 언어도 있다.
- 예를 들어 PHP는 기본적으로 멀티스레드를 사용할 수 없다.
- 모든 것이 순서대로 실행되고 입출력을 사용하면 끝날 때까지 기다려야 한다.
- 하지만 이런 제약은 시스템이 단순하다는 장점이기도 하다.
- 스레드가 하나면 타임라인도 하나이지만, 네트워크를 통한 API 호출 같은 것은 다른 타임라인이 필요하다.
- 하지만 메모리를 공유하지 않기 때문에 공유 자원을 많이 없앨 수 있다.
- 단일 스레드, 비동기
- 자바스크립트는 스레드가 하나이다.
- 입출력 작업을 하려면 비동기 모델을 사용해야 한다.
- 입출력의 결과는 콜백으로 받을 수 있지만, 언제 끝날지 알 수 없으므로 다른 타임라인에 표현해야 한다.
- 멀티스레드
- 자바나 파이썬, 루비, C, C#과 같은 많은 언어가 멀티스레드를 지원한다.
- 멀티스레드는 실행 순서를 보장하지 않기 때문에 프로그래밍하기 매우 어렵다.
- 새로운 스레드가 생기면 새로운 타임라인을 그려야 한다.
- 메시지 패싱 프로세스
- 엘릭서나 얼랭 같은 언어는 서로 다른 프로세스를 동시에 실행할 수 있는 스레드 모델을 지원한다.
- 프로세스는 서로 메모리를 공유하지 않고 메시지로 통신한다.
- 서로 다른 타임라인에 있는 액션은 순서가 섞이지만, 메모리를 공유하지 않기 때문에 가능한 실행 순서가 많아도 문제가 되지 않는다.
# 3. 타임라인 다이어그램으로 알 수 있는 것
# (1) 순서대로 실행되는 코드에도 두 가지 종류가 있다.
- 순서가 섞일 수 있는 코드
- 두 액션 사이에 시간은 얼마나 걸릴지 알 수 없다.
- 액션은 박스로 표시하고 액션 사이에 걸리는 시간은 선으로 표시한다.
- 그래서 액션과 액션 사이에 걸리는 시간에 따라 선을 길게 그릴 수도 있고 짧게 그릴 수도 있다.
- 그렇다고 해도 두 액션 사이에 시간이 얼마나 걸릴 지 알 수 없다.
- 그러므로 다른 타임라인의 액션과 순서가 섞일 수 있다.
- 순서가 섞이지 않는 코드
- 어떤 경우에는 두 액션이 차례로 실행되는데 그 사이에 다른 작업이 끼어들지 못한다.
- 런타임이 원래 해주거나 프로그래밍을 잘해서 만들 수 있다.
- 이런 경우는 액션을 같은 상자에 그린다.
# (2) 동시에 실행되는 코드는 순서를 예측할 수 없다.
- 동시에 실행되는 코드는 타임라인 다이어그램에 나란히 표현한다.
- 다이어그램에 나란히 표현되지만 두 액션이 항상 정확히 동시에 실행된다는 의미는 아니다.
- 타임라인에서 나란히 표현된 액션은 아래와 같이 세 가지 실행 순서를 가질 수 있다.
- 동시에 실행, 왼쪽 먼저, 오른쪽 먼저
- 타임라인 다이어그램을 볼 때 선의 길이나 액션이 정렬된 위치와 상관없이 위와 같은 순서가 가능하다고 생각해야 한다.
- 실행 가능한 순서는 문제가 될 수 있기 때문에 예상할 수 있어야 한다.
- 그래서 어떤 경우에는 명확한 설명을 위해 특정 순서를 강조해서 그릴 수도 있다.
- 여러 개의 타임라인은 시간에 따라 다양한 방식으로 실행될 수 있다.
- 타임라인이 실행 가능한 방법을 가능한 순서(possible ordering)라고 한다.
- 타임라인이 하나라면 실행 가능한 순서는 하나이다.
# 4. 좋은 타임라인의 원칙
실행 가능한 순서가 많다면 시스템을 이해하기 어렵다!
# (1) 타임라인은 적을수록 이해하기 쉽다.
- 타임라인이 하나인 시스템이 가장 이해하기 쉽다.
- 타임라인이 하나라면 모든 액션은 앞의 액션 다음에 바로 실행된다.
- 하지만 요즘 시스템에는 여러 타임라인이 필요하다.
- 멀티스레드나 비동기 콜배그 클라이언트-서버 간 통신 등을 사용하려면 새로운 타임라인이 필요하다.
- 타임라인 수를 줄인다면 훨씬 이해하기 쉬운 시스템이 된다.
- 하지만 항상 타임라인 수를 마음대로 조정할 수는 없다.
# (2) 타임라인은 짧을수록 이해하기 쉽다.
- 타임라인을 이해하기 쉽게 만드는 또 다른 방법은 타임라인의 단계를 줄이는 것이다.
- 단계를 줄인다면 실행 가능한 순서의 수도 많이 줄일 수 있다.
# (3) 공유하는 자원이 적을수록 이해하기 쉽다.
- 서로 다른 타임라인에 있는 두 액션이 서로 자원을 공유하지 않는다면 실행 순서에 신경 쓸 필요가 없다.
- 실행 가능한 순서의 개수가 줄어들지는 않지만, 신경 써야 할 실행 가능한 순서를 줄일 수 있다.
- 타임라인이 두 개 있다면 서로 자원을 공유하는 액션을 주의 깊게 봐야 한다.
# (4) 자원을 공유한다면 서로 조율해야 한다.
- 공유 자원을 많이 없앤다고 해도 여전히 없앨 수 없는 공유 자원이 남는다.
- 타임라인은 공유 자원을 안전하게 공유할 수 있어야 한다.
- 안전하게 공유한다는 말은 올바른 순서대로 자원을 쓰고 돌려준다는 말이다.
- 타임라인 간 조율은 올바른 결과를 주지 않는 실행 순서를 없애는 것을 말한다.
# (5) 시간을 일급으로 다룬다.
- 액션의 순서와 타이밍을 맞추는 것은 어렵다.
- 타임라인 다루는 재사용 가능한 객체를 만들면 타이밍 문제를 쉽게 만들 수 있다.
# 5. 자바스크립트의 이모저모
# (1) 자바스크립트의 단일 스레드
- 자바스크립트는 스레드가 하나이다.
- 전역변수를 바꾸는 동기 액션은 타임라인이 서로 섞이지 않는다.
- 비동기 호출은 미래에 알 수 없는 시점에 런타임에 의해 실행된다.
- 두 동기 액션은 동시에 실행되지 않는다.
# (2) 자바스크립트의 비동기 큐
자바스크립트의 이벤트 루프 관련 참고 페이지 (바로 가기 (opens new window))
- 기본 개념
- 브라우저에서 동작하는 자바스크립트 엔진은 작업 큐(job queue)라고 하는 큐를 가지고 있다.
- 작업 큐는 이벤트 루프(event loop)에 의해 처리된다.
- 이벤트 루프는 큐에서 작업 하나를 꺼내 실행하고 완료되면 다음 작업을 꺼내 실행하는 것을 무한히 반복한다.
- 이벤트 루프는 하나의 스레드에서 처리하기 때문에 두 개의 작업이 동시에 실행될 수 없다.
- 작업이란?
- 작업 큐에 있는 작업은 이벤트 데이터와 이벤트를 처리할 콜백으로 구성되어 있다.
- 이벤트 루프는 이벤트 데이터를 인자로 콜백을 부른다.
- 콜백은 이벤트 루프가 실행할 함수다.
- 이벤트 루프는 단순히 첫 번째 인자에 이벤트 데이터를 넣어 콜백 함수를 실행한다.
- 작업은 큐에 어떻게 들어가는가
- 이벤트가 발생하면 큐에 작업이 추가된다.
- 이벤트는 마우스 클릭이나 키보드 입력, AJAX 이벤트 같은 것을 말한다.
- 만약 콜백 함수가 있는 버튼에 이벤트가 발생하면 콜백 함수와 이벤트 데이터가 큐에 추가된다.
- 마우스 클릭처럼 어떤 이벤트도 예상할 수 없기 때문에 이벤트는 예측 불가능한 시점에 작업 큐에 들어간다.
- 들어간 작업은 작업 큐에서 나중에 온전히 가져온다.
- 작업이 없을 때 엔진은 무엇을 하는가
- 처리할 작업이 없는 경우도 있다.
- 이벤트 루프는 대기 상태로 들어가고 전원을 아낀다.
- 또는 가비지 컬렉션 같은 관리 작업을 하기도 한다.
- 이것은 브라우저 개발자에게 달려있다.
# (3) AJAX와 이벤트 큐
- 기본 개념
- 자바스크립트에서 AJAX 요청을 만들면 네트워크 엔진이 AJAX 요청을 처리하기 위해 요청 큐에 넣는다.
- 요청 큐에 작업이 추가되어도 코드는 계속 실행된다.
- 요청이 완료될 때까지 기다릴 필요가 없다.
- 많은 언어가 요청이 완료되어야 다음 코드를 진행할 수 있는 동기 요청 방식이지만 자바스크립트에서 AJAX를 사용하는 부분은 비동기이다.
- 네트워크 환경은 예측할 수 없기 때문에 응답은 요청 순서대로 오지 않는다.
- AJAX 콜백도 요청 순서와 상관없이 작업 큐에 들어간다.
- 요청에 대한 응답을 기다리지 않으면 응답을 어떻게 받는가
- AJAX 요청을 만들 때 요청에 관련된 다양한 이벤트 콜백을 등록할 수 있다.
- 요청이 처리되는 동안 네트워크 엔진에 의해 다양한 이벤트가 발생한다.
- 많이 사용하는 이벤트는
load
와error
이다. load
는 응답이 모두 다운로드 되었을 때 발생하는 이벤트,error
는 뭔가 잘못된 경우에 발생한다.
# 6. 타임라인 단순화하기
- 자바스크립트에서 단순화하는 방법
- 하나의 타임라인에 있는 모든 액션을 하나로 통합한다.
- 자바스크립트는 스레드가 하나이기 때문에 액션은 순서가 섞이지 않고 하나의 타임라인에서 실행된다.
- 타임라인은 다른 타임라인이 실행되기 전에 완료된다.
- 다이어그램에 점선이 있다면 타임라인 끝으로 옮긴다.
- 타임라인이 끝나는 곳에서 새로운 타임라인이 하나 생긴다면 통합한다.
- 하나의 타임라인에 있는 모든 액션을 하나로 통합한다.
# 📌 지금까지 내용 요약 정리
# (1) 액션을 확인하기
- 모든 액션은 타임라인에 표시되어야 한다.
- 복합적인 액션도 있으므로 변수를 읽고 쓰는 것처럼 하나의 액션처럼 보이지만 여러 액션으로 되어 있는 액션을 하나의 액션으로 파악하기 위해 주의 깊게 봐야 한다.
# (2) 액션을 그리기
- 순서대로 실행되는 액션: 하나가 끝나고 다음이 시작
- 순서대로 실행되는 액션은 같은 타임라인에 표시한다.
- 동시에 실행되는 액션: 동시에 실행되거나 왼쪽 먼저 또는 오른쪽 먼저 실행
- 동시에 실행되거나 순서가 섞여서 실행되는 겨우 분리된 타임라인으로 표시한다.
- 비동기 콜백, 멀티 프로세스, 멀티스레드, 여러 장치 등의 경우에 액션이 동시에 실행될 수 있다.
- 모든 액션을 그린 후 실행 순서를 제한하기 위해 점선을 사용할 수 있다.
- 예를 들어 ajax 콜백은 ajax 요청 전에 실행할 수 없다.
# (3) 타임라인을 단순화하기
- 순서가 섞이지 않는 두 액션은 하나의 박스로 합친다.
- 타임라인 끝에서 새로운 타임라인이 하나만 생긴다면 하나로 합친다.
- 순서에 제약이 있는 경우 점선을 추가한다.
# (4) 타임라인 읽기
- 일반적으로 서로 다른 타임라인에 있는 액션은 세 가지 순서로 실행될 수 있다.
- 동시에 실행되거나 왼쪽이 먼저 실행되거나 오른쪽이 먼저 실행될 수 있다.
- 이런 경우 실행 순서는 불가능하거나 기대한 대로이거나 잘못된 결과를 가져올 수 있다.
# 7. 자원을 공유하는 타임라인은 문제가 생길 수 있습니다
- 공유하는 자원을 없애 문제를 해결할 수 있다.
- 두 타임라인이 같은 전역변수를 사용하면 실행 순서가 섞인 상태에서도 각 타임라인이 전역변수에 접근할 수 있어 문제가 생길 수 있다.
- 그래서 이러한 전역변수를 지역변수로 바꾸는 것이 좋다.
- 혹은 전역변수에 접근하는 부분을 함수의 인자로 바꿔 해결할 수 있다.
# 8. 비동기 호출에서 명시적인 출력을 위해 리턴값 대신 콜백을 사용할 수 있다
- 비동기 호출에서 결괏값을 리턴값으로 줄 수 없다.
- 비동기 호출은 바로 리턴이 되지만 결괏값은 콜백이 호출되어야 얻을 수 있기 때문이다.
- 비동기 호출해서 결과를 받을 수 있는 방법은 콜백을 사용하는 것이다.
- 결과가 준비되었을 때 결과를 인자에 넣어 콜백을 호출한다.
- 동기화된 함수에서 액션을 빼낼 때 액션을 호출하는 대신 액션에 넘기는 인잣값을 리턴했다.
- 그리고 호출하는 곳에서 리턴값을 받아 액션을 호출했다.
- 비동기 함수에서는 리턴값대신 콜백을 사용한다.