이전 내용 요약 (저번주 찬원님 부분)
문제: 장바구니 금액 계산 코드 최적화 이후 타이밍 버그 발생
해결책: 다이어그램 그리기 → 실행 가능한 순서 분석을 통한 문제 파악
실행 가능한 순서 분석하기 & 왜 지금 타임라인이 더 빠를까요? (p483~4)
// (...)
function calc_cart_total(cart, callback) {
var total = 0;
1. cost_ajax: 장바구니에 제품 가격을 합산
cost_ajax(cart, function(cost) {
total += cost;
2. shipping_ajax: 장바구니에 배송비를 합산
shipping_ajax(cart, function(shipping) {
total += shipping;
callback(total);
});
});
}
// (...)
JavaScript
복사
// (...)
function calc_cart_total(cart, callback) {
var total = 0;
1. cost_ajax: 장바구니에 제품 가격을 합산
cost_ajax(cart, function(cost) {
total += cost;
});
2. shipping_ajax: 장바구니에 배송비를 합산
shipping_ajax(cart, function(shipping) {
total += shipping;
callback(total);
});
}
// (...)
JavaScript
복사
쉬는 시간 (p485)
먼저 요청한 cost_ajax 요청의 응답이 shipping_ajax 요청의 응답보다 가끔 늦어 지는 이유
문제를 찾기 위해 많은 단계가 필요한데, 모든 단계의 타임라인을 그려야 하나요?
모든 병렬 콜백 기다리기 (p486)
타임라인을 나누기 위한 동시성 기본형 (p487)
Cut() (≒ Promise.all())
Cut()의 코드
function Cut(num, callback) {
var num_finished = 0;
return function() {
num_finished += 1;
if(num_finished === num) callback();
};
}
JavaScript
복사
Cut() 세부 분석
1. 기다릴 타임라인의 수
2. 최종적으로 실행할 콜백
function Cut(num, callback) {
3. 카운터를 0으로 초기화
var num_finished = 0;
return function() {
4. 함수를 호출할 때마다 카운터 증가
num_finished += 1;
5. 마지막 타임라인이 끝났을 때 콜백을 호출
if(num_finished === num) callback();
};
}
JavaScript
복사
코드에 Cut() 적용하기 (p489)
Cut()을 보관할 범위
→ 실행 순서 문제가 발생하는 두 함수를 포함하는 calc_cart_total() 함수
Cut()에 어떤 콜백을 넣을 지
→ 기존에 total 값 계산이 끝났을 때 최종적으로 호출 되는 함수 (callback: 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);
});
}
JavaScript
복사
function calc_cart_total(cart, callback) {
var total = 0;
var done = Cut(2, function() {
callback(total);
});
cost_ajax(cart, function(cost) {
total += cost;
done();
});
shipping_ajax(cart, function(shipping) {
total += shipping;
done();
});
}
JavaScript
복사
쉬는 시간 (p490)
Cut()은 정말 잘 작동하나요?
Cut()은 정말 작은 코드입니다. 이렇게 간단한 코드가 유용할 수 있나요?
Promise처럼 다른 것을 사용하는 것이 더 좋지 않나요?
불확실한 순서 분석하기 (p491)
→ Cut() 적용 후 모든 경우에 대해 정상적인 결과 반환!!
Cut() 적용 후 타임라인
Cut() 적용 후 경우의 수
병렬 실행 분석 (p492)
→ 속도 개선과 동시에 타이밍 버그도 해결
여러 번 클릭하는 경우 분석 (p493)
→ 정상적으로 동작하나 타임라인은 복잡해짐…
이러한 복잡성이 왜 생기는 것인지?
1. 비동기 웹 요청(ajax) → ajax 사용안할 시 새로고침 다수 발생
2. 결과를 합쳐야 하는 API 응답 → 한 개의 API로 요청 시 서버로 복잡성을 단순히 옮기는 꼴
3. 예측 불가능한 사용자의 액션 → 사용자에게 순차적인 flow 강요 시 나쁜 유저경험 하게 됨
“결국 복잡성을 다루는 좋은 프로그래밍 기술이 필요”
딱 한 번만 호출하는 기본형 (p500)
문제: 제품을 처음 장바구니에 추가 시에만 메세지 보내는 기능 개발 필요
해결책: 여러 번 호출해도 한 번만 실행되는 동시성 기본형 도입
JustOnce() (≒ debouncing)
debouncing vs. throttling 설명 링크 (https://www.zerocho.com/category/JavaScript/post/59a8e9cb15ac0000182794fa)
JustOnce()의 코드
function JustOnce(action) {
var alreadyCalled = false;
return function(a, b, c) {
if(alreadyCalled) return;
alreadyCalled = true;
return action(a, b, c);
};
}
JavaScript
복사
JustOnce() 세부 분석
1. 액션을 전달
function JustOnce(action) {
2. 함수가 실행됐는지 기억
var alreadyCalled = false;
return function(a, b, c) {
3. 실행한 적이 있다면 바로 종료
if(alreadyCalled) return;
4. 함수가 실행 됬다고 생각하고 실행 사실 기록
alreadyCalled = true;
5. 액션 호출
return action(a, b, c);
};
}
JavaScript
복사
•
자바스크립트는 단일스레드 언어 → 타임라인은 다른 타임라인 시작 전 완료
•
다른 언어에서는 타임라인 조율을 위해 락(lock)이나 다른 기능 필요
•
최초 한 번만 효과가 발생하는 액션
•
JustOnce는 어떤 액션이든 멱등원으로 만들어 줌
암묵적 시간 모델 vs 명시적 시간 모델 (p502)
암묵적 시간 모델
모든언어가 기본적으로 제공
원하는대로 실행 방식 커스텀은 불가 (간단한 프로그램에서는 유용)
명시적 시간 모델
함수형 개발자가 필요에 따라 만듬
필요한 실행 방식에 동작 하도록 할 수 있음
1. Queue()
: 비동기 콜백 사용 시 새로운 타임라인을 만들지 않도록 함
2. JustOnce()
: 여러 번 호출해도 한 번만 실행
JavaScript
복사
쉬는 시간 (p504)
앞에서 만든 동시성 기본형이 모두 고차 함수인데 모든 동시성 기본형은 고차함수로 만들어야 하나요?
다섯 번째 원칙에서 ‘시간을 다룬다’라는 말이 있습니다. 조금 과장된 표현이 아닌가요?
요약: 타임라인 사용하기 (p507)
1. 타임라인 수 줄이기: 서버 요청 줄이기 → 시스템 단순화
2. 타임라인 길이 줄이기: 액션을 계산(타임라인에 미표시)으로 바꾸기 → 타임라인 단순화
3. 공유 자원을 없애기: 자원을 공유하지 않는 타임라인은 순서문제 X
4. 동시성 기본형으로 자원 공유: 큐나 락을 이용해 자원을 안전하게 공유
5. 동시성 기본형으로 조율: Promise나 Cut을 이용 액션의 순서나 반복을 제한
Chap. 18 - 반응형 아키텍처와 어니언 아키텍처
두 아키텍처 패턴은 독립적입니다
반응형 아키텍처 (≒ Redux의 store)
•
순차적 액션 단계에 활용
•
효과와 원인을 분리 → 코드의 복잡하게 꼬인 부분을 풀어줌
어니언 아키텍처
•
서비스의 모든 단계에 사용
•
현실 세계와 상호작용하는 서비스 구조를 만듬