Brolog
Javascript

Promise.all과 구조 분해 할당을 활용한 데이터 처리 패턴

비동기 요청 결과를 구조 분해하고 객체 형태로 매핑하는 JavaScript 데이터 처리 방식 분석

가독성과 퍼포먼스를 모두 잡는 모던 자바스크립트 비동기 패턴

자바스크립트에서 복수의 비동기 데이터(API, 파일 시스템 등)를 처리할 때 단순히 await를 순차적으로 나열하는 방식은 동기적 정체를 유발한다. 모던 자바스크립트(ES6+)는 Promise.all과 구조 분해 할당(Destructuring Assignment)을 결합하여, 여러 비동기 요청을 병렬로 처리함과 동시에 결과 배열의 깊은 오브젝트 내부 속성까지 한 줄로 추출하는 압도적인 표현력을 제공한다.


1. 순차적 await와 병렬 Promise.all의 실행 흐름 차이

독립적인 비동기 연산 여러 개를 연이어 수행할 때, 직관적으로 작성된 코드는 대개 앞선 연산이 끝나기를 기다리는 병목을 발생시킨다.

// ❌ 순차적 실행: 총 2초 이상 소요 (비효율적 패턴)
const postsResult = await useAsyncData('posts', ...)  // 1초 대기
const navResult = await useAsyncData('nav', ...)    // 앞선 연산 종료 후 1초 대기

반면 Promise.all은 인자로 전달된 프라미스 배열을 동시에 트리거하여 병렬 레이싱 상태로 만든다. 모든 프라미스가 이행(Fulfilled)되는 시점에 결과물들을 원본 요청 순서에 맞는 배열로 반환한다.

// ✨ 병렬 실행: 동시에 출발하여 총 1초 소요
const results = await Promise.all([
  useAsyncData('posts', ...),
  useAsyncData('nav', ...)
])
// results => [posts의 결과 오브젝트, nav의 결과 오브젝트]

2. 구조 분해 할당(Destructuring)의 핵심 메커니즘

구조 분해 할당은 배열 리터럴([ ])이나 객체 리터럴({ })의 형태를 대입 연산자 좌항에 선언하여, 우항의 복잡한 데이터 구조에서 원하는 알맹이만 골라내어 개별 변수에 직접 바인딩하는 문법이다.

이 문법은 단순히 인덱스 코드(results[0])나 점 표기법(results.data)을 줄여주는 단축 표기 이상의 의미를 지니며, 코드의 선언적인 성격을 극대화한다.

📦 1) 배열 구조 분해 할당의 순서 매핑

Promise.all이 리턴한 결과물은 순서가 보장된 배열이다. 좌항에 배열 형태를 선언하면 우항 배열의 원소들이 인덱스 순서에 따라 변수에 차례대로 맵핑된다.

// 배열의 0번째와 1번째 알맹이를 각각의 변수로 즉시 분리
const [postsResult, navResult] = await Promise.all([
  useAsyncData('posts', ...),
  useAsyncData('nav', ...)
])

🗂️ 2) 객체 구조 분해 할당과 키(Key) 매핑

배열과 다르게 객체 구조 분해 할당은 순서가 아닌 **프로퍼티 키(Key)**를 기준으로 매핑이 일어난다. 데이터 구조의 순서가 바뀌어도 타겟 키의 이름만 일치하면 정확하게 값을 찾아온다.


3. 중첩된 객체 구조 분해와 변수명 재정의(Aliasing) 및 기본값 설정

비동기 페칭 라이브러리나 상태 관리 도구는 순수 데이터 배열뿐만 아니라 로딩 상태, 에러 객체 등을 포함한 거대한 래퍼 오브젝트를 반환한다. 예를 들어 반환 유형이 { data: [...], pending: false, error: null } 구조라면, 이 중 오직 data라는 특정 키(Key)의 값만 표출하여 새로운 이름을 부여하는 이중 분해가 가능하다.

🏷️ 변수명 재정의 (Aliasing)

객체 구조 분해 할당에서 { 원본키: 변경할변수명 } 문법을 적용하면, 타겟 상자 내부를 파고들어 알맹이를 추출함과 동시에 현재 런타임 스코프 내에서 식별 충돌을 피할 수 있는 고유 상수를 정의할 수 있다.

// 객체 안의 data 속성을 찾아서 변수 posts에 할당하는 단독 연산
const { data: posts } = await useAsyncData('posts', ...)

🛡️ 안전망을 위한 기본값(Default Value) 지정

구조 분해 할당 시 우항의 객체나 배열에 끄집어내려는 값이 존재하지 않을 경우(undefined), 이를 방어하기 위한 기본값을 대입 연산자(=)로 미리 선언해 둘 수 있다. 비동기 통신 장애나 빈 데이터 레이아웃을 다룰 때 대단히 유용하다.

// 데이터가 없을 경우를 대비해 빈 배열([])을 기본값으로 안전하게 바인딩
const { data: posts = [] } = await useAsyncData('posts', ...)

4. 최종 합체: 복합 중첩 구조 분해의 해부

배열 구조 분해 할당 내부에 객체 구조 분해 할당과 기본값 설정을 한꺼번에 엮어 복합적으로 중첩시키는 최종 형태는 다음과 같은 메커니즘으로 동작한다.

const [
  { data: posts = [] },    // 1. 0번째 결과 객체의 'data'를 추출하여 'posts'라 칭하고, 없을 시 [] 대입
  { data: navData = [] }   // 2. 1번째 결과 객체의 'data'를 추출하여 'navData'라 칭하고, 없을 시 [] 대입
] = await Promise.all([
  useAsyncData('main-posts-feed', ...), // 0번째 방으로 진입
  useAsyncData('main-posts-nav', ...)   // 1번째 방으로 진입
])

🔍 동작 프로세스 시각화

  1. 병렬 요청: Promise.all 내부의 비동기 함수들이 네트워크 컨텍스트 상에서 병렬로 호출된다.
  2. 배열 수집: 연산이 모두 만료되면 비동기 엔진은 두 개의 응답 객체를 원소로 가진 하나의 결과 배열을 빌드한다.
  3. 배열 분해: 좌항의 [ 문법이 가동되어 0번째 객체와 1번째 객체를 인덱스 기반으로 격리한다.
  4. 객체 투과 및 매핑: 각 객체 내부의 고유 속성인 data 필드를 찾아 관통한 뒤, 만약 값이 유효하지 않다면 미리 세팅된 기본값(= [])을 반영하여 최종적으로 postsnavData라는 로컬 상수에 데이터를 안전하게 바인딩한다.

📌 요약

  • 자바스크립트의 복합 구조 분해 할당 문법은 여러 줄에 걸쳐 임시 변수를 생성하고 프로퍼티에 접근해야 했던 중복 코드를 완벽하게 제거한다.
  • Promise.all의 병렬 성능 최적화 이점을 완전히 누리면서도, 중첩된 응답 객체 내부의 핵심 상태(Reactivity State)만을 명확하게 필터링하고 변수명 치환 및 기본값 방어까지 한 줄로 끝내는 최적의 DX(개발자 경험)를 보장한다.
Copyright © 2026 Brolog. All rights reserved.