프로모 가격, 없으면 정가

FxDart 승 async

요구사항

8월 프로모 가격표에 대고 구매 주문 두 건의 견적을 내세요. 비동기 조회는 프로모 가격이 없는 SKU에 대해 던집니다 — 그런 라인은 정가로 폴백해야 하고, 모든 라인이 견적에 나타나야 합니다. 라인이 없는 주문은 (no lines to quote) 한 줄로 견적됩니다. 데이터는 아래 코드에 있으며, 두 버전 모두 예상 출력 아래에 표시된 줄들을 출력해야 합니다.

예상 출력
PO-3391:
  SKU-201: 11.50 (promo)
  SKU-333: 9.50 (list)
  SKU-204: 8.25 (promo)
  SKU-207: 19.90 (promo)
  SKU-410: 5.20 (list)
PO-3402:
  (no lines to quote)

나란히 보기

RxDart

FxDart

차이가 나는 이유

스트림은 값과 에러를 별도 채널로 실어 나르고, 에러 채널은 파이프라인 전체의 소유입니다. asyncMap 뒤에 놓인 onErrorReturnWith가 실패를 보았을 때쯤이면, 그것을 일으킨 라인은 이미 사라지고 없을 것입니다 — 에러 이벤트는 에러를 실어 나르지, 요소를 실어 나르지 않으니까요. 관용적인 RxDart 복구는 모든 조회에 자기만의 내부 스트림을 주는 것입니다 — flatMap으로 Rx.fromCallable에 들어가서 — 그러면 각 실패는 자기만의 한 항목짜리 스트림에만 종결적이고, 그 안에서는 라인이 아직 스코프에 있어 폴백할 수 있습니다.

pull 모델에는 사이로 떨어질 두 번째 채널이 없습니다. 조회는 map 콜백 안의 await이므로, 복구는 평범한 Dart 제어 흐름입니다: 호출 바로 옆에서 타입 있는 StateError를 잡아 정가를 반환하면 됩니다 — 요소, 그 폴백, 에러 처리가 모두 같은 네 줄 안에 삽니다. 감싸기도 재병합도 없고, 실패는 파이프라인에 아예 닿지 않습니다.

비어 있는 두 번째 주문은 양쪽에서 같은 방식으로 착지합니다 — defaultIfEmpty, FxDart가 Rx에서 가져온 연산자입니다. 본 경기에 대한 판정은 FxDart에게 갑니다: 항목별 에러 복구가 pull 모델에서는 한 문장이고, push 모델에서는 하나의 공사입니다.

벤치마크

Apple M1 Max, RAM 32 GB · Dart 3.12.2 (AOT 컴파일) · 2026-08-18

비동기 예제입니다. 대표 스케일이 1,000,000이 아니라 N = 10,000인 이유 — 원소 하나마다 양쪽 모두 이벤트 루프를 한 바퀴 돌아야 하므로, 실제 await 백만 번은 파이프라인이 아니라 Dart 이벤트 루프를 몇 분씩 재게 됩니다. 지연은 0으로 두고 예제의 동시성 제한은 그대로 유지합니다. 막대가 비교하는 것은 파이프라인 기계 장치 자체입니다.

N = 100

시간 무승부

RxDart 455 µs
FxDart 453 µs

최대 메모리 무승부

RxDart 17.1 MB
FxDart 17.3 MB

N = 10,000

시간 FxDart 승

RxDart 42.7 ms
FxDart 38.9 ms

최대 메모리 RxDart 승

RxDart 49.1 MB
FxDart 52.0 MB

막대는 사이드별로 새 프로세스에서 반복 측정한 중앙값입니다(작은 N은 타이머 해상도를 위해 배치 처리). 두 사이드가 서로 5% 이내이거나 — 사람이 지각할 수 없는 차이인 0.6ms 이내이면 — 무승부로 칩니다. 상대 차이가 근소한 경우는 최대 5회까지 다시 측정합니다. 앱에서는 어느 막대가 짧든 몇 밀리초 이하의 차이는 사용자에게 보이지 않습니다. 메모리는 프로세스 최대 RSS입니다. Dart VM과 데이터셋은 양쪽이 동일하므로, 두 막대의 차이가 곧 파이프라인 자체가 붙들고 있는 양입니다.