타임라인 격리하기
이번 글에서는 시간에 따라 실행되는 액션의 순서를 나타내기 위해 타임라인 다이어그램에 대해서 알아보겠습니다.
스터디 회차: 14회차, 15회차 (2025년 9월 10일, 11일)
타임라인 다이어그램
타임라인 다이어그램이란
- 타임라인은 액션을 순서대로 나열한 것입니다.
- 타인라인 다이어그램은 시간에 따른 액션 순서를 시각적으로 표시한 것입니다.
규칙
- 두 액션이 순서대로 나타나면 같은 타임라인에 넣습니다.
- 두 액션이 동시에 실행되거나 순서를 에상할 수 없다면 분리된 타임라인에 넣습니다.
타임라인 그리기
타임라인 다이어그램을 그리는 과정
- 액션을 확인합니다.
- 각 액션을 그립니다.
- 단순화합니다.
예제: 사용자와 문서를 저장하는 로직
tsx
saveUserAjax(user, function () {
setUserLoadingDOM(false);
});
setUserLoadingDOM(true);
saveDocumentAjax(document, function () {
setDocLoadingDOM(false);
});
setDocLoadingDOM(true);1. 액션을 확인합니다
tsx
saveUserAjax();
setUserLoadingDOM(false);
setUserLoadingDOM(true);
saveDocumentAjax();
setDocLoadingDOM(false);
setDocLoadingDOM(true);2. 각 액션을 그립니다

- 자바 스크립트 코드는 위에서 아래로 실행됩니다.
- 아직 타임라인이 없기 때문에 새로운 타임라인을 만듭니다.

- 콜백안에 있는 코드입니다.
- 콜백은 비동기로 실행되기 때문에 요청이 끝나는 시점에 언젠가 실행됩니다.
- 비동기 콜백이기 때문에 새로운 타임라인이 필요합니다.

- 다음 실행되는 코드는 콜백이 아니므로 원래 타임라인에서 실행됩니다.

- 두번째 콜백함수의 경우는 새로운 타임라인에 추가하여 타임라인 다이어그램을 완성합니다.
3. 단순화합니다
- 하나의 타임라인에 있는 모든 액션을 하나로 통합합니다.
- 타임라인이 끝나는 곳에서 새로운 타임라인이 하나 생긴다면 통합합니다.

- 자바스크립트는 하나의 스레드이기 때문에 액션은 순서가 섞이지 않고 하나의 타임라인에서 실행됩니다. 따라서 하나로 통합할 수 있습니다.
- 타임라인이 끝나는 곳에 새로운 타임라인이 두개 생기기 때문에 통합하지 않습니다.
순서대로 실행되는 코드도 두 가지 종류가 있습니다

- 두 액션 사이에 시간이 얼마나 걸릴지 알 수 없는 코드는 순서가 섞일 수 있는 코드입니다.
- 두 액션이 차례로 실행되는데 그 사이에 다른 작업이 끼어들 수 없는 코드는 순서가 섞이지 않는 코드입니다.
- 이런 경우는 액션을 같은 상자에 그립니다.
동시에 실행되는 코드는 실행순서를 확신할 수 없습니다

- 동시에 실행되는 코드는 타임라인 다이어그램에 나란히 표현합니다.
- 하지만 항상 정확히 동시에 실행된다는 의미는 아닙니다.
- 따라서 다르게 그렸지만 모두 같은 것을 의미합니다.
예제2: 아이템을 장바구니에 추가하기
tsx
function add_item_to_cart(name, price, quantity) {
cart = add_item(cart, name, price, quantity);
calc_cart_total();
}
function calc_cart_total() {
total = 0;
cost_ajax(cart, function (cost) {
total += cost;
shipping_ajax(cart, function (shipping) {
total += shipping;
update_total_dom(total);
});
});
}1. 액션 확인하기
tsx
1. cart 읽기
2. cart 쓰기
3. total = 0 쓰기
4. cart 읽기
5. cost_ajax() 부르기
6. total 읽기
7. total 쓰기
8. cart 읽기
9. shipping_ajax() 부르기
10. total 읽기
11. total 쓰기
12. total 읽기
13. update_total_dom() 부르기+= 는 사실 세단계입니다
tsx
// 코드
total += cost;
// 실제 연산
var temp = total; // total 읽기
temp = temp + cost; // 계산
total = temp; // total 쓰기- 모두 세단계로 이루어져 있습니다.
- total 값이 전역변수라면 첫번째 단계와 세번째 단계는 액션입니다.
- 따라서 두 개의 액션으로 다이어그램에 표시해야 합니다.
2. 다이어그램 그리기

- 액션이 순서대로 실행되면 같은 타임라인에 그립니다.
- 액션이 동시에 실행되면 새로운 타임라인에 그립니다.
3. 단순화하기

- 자바스크립트는 하나의 스레드에서 실행되기 때문에 모든 액션을 박스 하나에 넣을 수 있습니다.
- 비동기 액션 이후에 연속되는 콜백이 하나라면 하나의 타임라인으로 통합할 수 있습니다.
모든 액션을 하나의 박스로 넣을수 있을까요?
- 다시 단순화하기 첫번째 단계를 적용해서 모든 액션을 하나의 박스로 넣을 수 있을까요?
- 그럴 수 없습니다.
- 만약 다른 타임라인에 액션이 생긴다면 각 박스는 순서가 섞일 가능성이 있기 때문입니다.
자원을 공유하는 타임라인은 문제가 생길 수 있습니다
예제: 장바구니에 아이템 담는 것을 빠르게 두 번 실행

- 빠르게 두번 실행해서 순서가 섞이게 되면 기대와 다른 연산 결과가 나올 수 있습니다.
- 문제는 공유하는 자원 때문에 발생합니다.
전역 변수를 지역 변수로 바꾸기

- total 값이 0이 아닐수 있습니다. 전역 변수이기 때문에 다른 타임라인에서 값을 바꿀 수 있습니다.
- 지역 변수로 바꾼 다음에는 함수 밖으로 영향을 주지 않기 때문에 더이상 액션이 아닙니다.
- 따라서 타임라인에서 제거할 수 있습니다.
전역 변수를 인자로 바꾸기

- calc_cart_total 안에서 사용하는 두개의 cart는 전역 벼수를 참조하고 있습니다. 두개의 코드 사이에 cart가 변경된다면 예상치 못한 결과가 나올 수 있습니다.
- 인자로 변경하여 같은 cart에 대해서 동작하도록 수정할 수 있습니다.
- 따라서 cart는 서로 다른 타임라인에 영향을 주지 않습니다.
함수 본문을 콜백으로 바꾸기
tsx
function add_item_to_cart(name, price, quant) {
cart = add_item(cart, name, price, quant);
calc_cart_total(cart);
}
function calc_cart_total(cart) {
var total = 0;
cost_ajax(cart, function (cost) {
total += cost;
shipping_ajax(cart, function (shipping) {
total += shipping;
update_total_dom(total);
});
});
}- 마지막으로, 계산된 결과를 반드시 update_total_dom 을 실행하지 않고 다른 동작을 수행할 수 있으므로 이 부분을 개선할 수 있습니다.
- total 값을 리턴하는 방법은, 비동기 호출이 끝나야 결과가 나오기 때문에 리턴하는 방법은 사용할 수 없습니다.
- 따라서 함수 본문을 콜백으로 바꾸기 리팩토링을 통해 비동기 호출의 결과로 실행할 함수를 전달받아 개선할 수 있습니다.
tsx
function add_item_to_cart(name, price, quant) {
cart = add_item(cart, name, price, quant);
calc_cart_total(cart, update_total_dom);
}
function calc_cart_total(cart, callback) {
var total = 0;
cost_ajax(cart, function (cost) {
total += cost;
shipping_ajax(cart, function (shipping) {
total += shipping;
callback(total);
});
});
}- 이제 total 값을 다른 계산에서도 사용할 수 있습니다.
async/await을 사용해서 개선할 수 있지 않나요?
tsx
async function calc_cart_total(cart, callback) {
var total = 0;
const cost = await cost_ajax(cart);
total += cost;
const shipping = await shipping_ajax(cart);
total += shipping;
return total;
}- 책의 내용과 별개로 최근에는
async/await을 사용해 비동기 코드를 동기 코드처럼 작성할 수 있습니다. - 이는 코드 가독성을 높이고 흐름을 직관적으로 만듭니다.
tsx
async function add_item_to_cart(name, price, quant) {
cart = add_item(cart, name, price, quant);
const total = await calc_cart_total(cart); // total이 계산될때까지 기다림
update_total_dom(total);
// total, dom 업데이트와 상관없는 로직
}- 하지만 모든 코드를 기다리게 하므로 필요 없는 경우 병목 현상을 일으킬 수 있습니다.
- 따라서 상황에 따라
callback방식과async/await방식을 적절히 선택하는 것이 중요합니다.
정리하기
- 타임라인 다이어그램은 비동기 코드의 실행 순서를 시각적으로 표현하는 도구입니다.
- 타임라인 다이어그램의 기본 규칙
- 순차적으로 실행되는 코드는 같은 타임라인에 넣는다.
- 동시에 실행되거나 실행 순서를 확신할 수 없는 코드는 별도의 타임라인으로 분리한다.
- 타임라인 다이어그램을 그리는 과정
- 액션을 확인합니다.
- 각 액션을 그립니다.
- 단순화합니다.
- 공유 자원 문제
- 여러 타임라인에서 같은 전역 변수를 다루면 값이 꼬이거나 예상치 못한 결과가 발생한다.
- 이를 해결하기 위해서는
- 전역 변수를 지역 변수로 바꾸거나,
- 전역 변수를 함수 인자로 전달하거나,
- 함수 본문을 콜백으로 바꿔서 안전하게 실행 흐름을 제어하는 방법을 사용할 수 있다.
