지난 주에 타임라인 다이어그램이라는 개념을 읽었다.
비동기 환경에서 작업 순서를 시각화 하는 이 다이어그램은,
흐름을 이해하고 문제를 디버깅 하는데 유용한 친구였다.
하지만 단순히 다이어그램만 그린다고 문제가 사라지는 것은 아니다.
이번 주에는 그 흐름을 어떻게 제어할 것인가,
즉 실제 문제를 해결하는 방법에 대해서 정리할 것이다.
⁉️ 자바스크립트에 큐 자료구조가 없다?
사실 나도 처음 알았다.
자바스크립트에는 Queue라는 내장 자료구조가 없다.
큐 자료구조는 간단하게 설명하면 선입선출(FIFO)을 의미하는데,
다행히 배열 메서드로 선입 선출 방식의 큐를 흉내낼 수 있다.
const queue = [];
queue.push("A"); // 데이터 넣기
queue.push("B");
console.log(queue.shift()); // A
- push() → 뒤에 추가
- shift() → 앞에서 꺼냄
주의할 점은 shift()는 배열의 맨 앞 요소를 제거하면서 나머지 요소를 전부 앞으로 밀어내기 때문에 성능상 비용이 크다.
그래서 고성능이 필요한 상황에서는 큐를 직접 구현하거나, linked list 구조로 대체하는게 더 좋다고 한다.
서론이 조금 길었지만 이 이야기를 왜 시작했냐면...
비동기 환경에서 처리를 하기 위해서 이다.
⚙️ 비동기 환경에서 큐가 필요한 이유
📌 예시
- A와 B라는 두 작업이 같은 자원(예: 장바구니)을 동시에 수정한다면?
→ 순서가 꼬이거나, 데이터가 중복되거나, 충돌이 일어날 수 있다.
이럴 때는 큐를 사용해서 자원 접근을 순차적으로 제어해야 한다
function Queue() {
const queue_item = [];
let working = false;
const runNext = () => {
if(working) return;
if(queue_item.length === 0) return;
working = true
const cart = queue_item.shift();
calc_cart_total(cart, (total)=>{
update_total_dom(total);
working = false;
runNext();
})
}
return (cart) => {
queue_item.push(cart);
setTimeout(runNext, 0);
}
}
비동기 작업을 한 번에 하나씩 처리하게 되므로, 동시성 문제를 방지할 수 있다.
만약, API 요청이 너무 많아 한꺼번에 처리할 수 없는 상황이 생기면?
➡ 이럴 땐 모든 요청을 기다리게 만들기보단, 일부 요청은 과감히 버리는 전략이 필요하다.
📌 예시
function DroppingQueue(limit) {
const queue = [];
let working = false;
const runNext = () => {
if (working) return;
if (queue.length === 0) return;
working = true;
const task = queue.shift();
task(() => {
working = false;
runNext();
});
};
return (task) => {
if (queue.length >= limit) {
console.warn("Queue is full. Dropping task.");
return;
}
queue.push(task);
setTimeout(runNext, 0);
};
}
- 제한된 용량을 가진 큐를 만들고
- 꽉 차면 새 작업은 거절하기
- 과부화 상황에도 안정적인 동작을 유지한다.
이런 구조가 왜 중요한가?
- 실시간 서비스는 안정성 보다는 응답속도가 중요한 경우가 많다
- 일정한 처리 속도를 유지하면서 시스템 과부화를 방지한다.
✂️ 타임라인 커팅
작업이 병렬로 실행될 수도 있지만,
특정 시점에서는 순서를 맞춰야 할 때도 있다.
우리는 이것을 타임라인 커팅이라고 부른다.
📌 예시
- A, B, C 작업은, B가 끝나야 A와 C가 실행될 수있다.
await Promise.all([doA(), doB(), doC()]);
// 모든 작업이 끝난 뒤 다음 단계로
// 함수형 스타일
go(
fetchData,
safeParseJson,
when(isValid, processData)
);
흐름은 비동기 이지만,
의도한 시점에 잘라내듯 특정지점에서 동기화 하는 설계가 필요하다.
🔈
사실 나는 이미 async/await를 자연스럽게 쓰고 있었지만,
오늘 큐를 직접 만들고 타임라인 흐름을 시각화해보니
내가 그동안 얼마나 많은 비동기 처리를 “당연하게” 넘겨왔는지 돌아보게 됐다.
await는 단순한 키워드가 아니라,
내 코드 안에 타임라인 커팅 지점을 새기는 설계 도구라는 걸 느꼈다.
앞으로는 동작 순서를 예측이 아니라 설계하는 자세로 코드를 짜야겠다는 생각이 들었다.
'FE > BOOK' 카테고리의 다른 글
[함수형코딩]WEEK10 반응형 아키텍처란? + 후기 (1) | 2025.06.02 |
---|---|
[함수형코딩]WEEK8 타임라인 다이어그램? (0) | 2025.05.14 |
[함수형코딩]WEEK7 함수형 도구 체이닝과 고차함수 (0) | 2025.05.07 |
[함수형코딩]WEEK6 일급함수, 너 뭐 돼? (0) | 2025.04.15 |
[함수형코딩]WEEK5 계층형 설계- 추상화의 벽, 작은 인터페이스, 편리한 계층 (0) | 2025.04.08 |