Promise

2025. 3. 30. 22:44Web Development/JavaScript

Promise

ES6에서 도입된 Promise는 비동기 작업의 최종 완료(또는 실패) 및 결과 값을 나타내는 객체입니다. 콜백 지옥 문제를 해결하고 더 나은 오류 처리를 제공합니다.

Promise 기본 개념

Promise는 다음 중 하나의 상태를 가집니다:

  • 대기(pending): 초기 상태, 이행되거나 거부되지 않음
  • 이행(fulfilled): 작업이 성공적으로 완료됨
  • 거부(rejected): 작업이 실패함
// Promise 생성
const myPromise = new Promise((resolve, reject) => {
  // 비동기 작업 수행
  const success = true;
  
  if (success) {
    resolve("작업 성공!"); // 이행 상태로 전환
  } else {
    reject(new Error("작업 실패!")); // 거부 상태로 전환
  }
});

// Promise 사용
myPromise
  .then(result => {
    console.log("성공:", result); // "성공: 작업 성공!"
  })
  .catch(error => {
    console.error("오류:", error);
  });

Promise 메서드

.then(), .catch(), .finally()

function fetchUser(userId) {
  return new Promise((resolve, reject) => {
    // 비동기 작업 (예: API 호출)
    setTimeout(() => {
      if (userId > 0) {
        resolve({ id: userId, name: `사용자${userId}` });
      } else {
        reject(new Error("유효하지 않은 사용자 ID"));
      }
    }, 1000);
  });
}

fetchUser(123)
  .then(user => {
    console.log("사용자 정보:", user);
    return user.id; // 다음 then으로 값 전달
  })
  .then(userId => {
    console.log("사용자 ID:", userId);
    throw new Error("의도적인 오류"); // 오류 발생
  })
  .catch(error => {
    console.error("처리 중 오류 발생:", error);
    return "오류 복구"; // catch 후에도 체인 계속
  })
  .then(value => {
    console.log("catch 이후 값:", value);
  })
  .finally(() => {
    console.log("성공 또는 실패 여부와 관계없이 항상 실행");
  });

Promise.all(), Promise.race(), Promise.allSettled()

// 여러 Promise 동시 처리
const promise1 = Promise.resolve("첫 번째 결과");
const promise2 = new Promise(resolve => setTimeout(() => resolve("두 번째 결과"), 1000));
const promise3 = fetch('https://api.example.com/data').then(res => res.json());

// Promise.all - 모든 Promise가 이행될 때까지 기다림 (하나라도 거부되면 즉시 거부됨)
Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log("모든 결과:", results); // [첫 번째 결과, 두 번째 결과, API 응답 데이터]
  })
  .catch(error => {
    console.error("하나 이상의 Promise가 거부됨:", error);
  });

// Promise.race - 가장 먼저 완료(이행 또는 거부)되는 Promise 결과를 반환
Promise.race([promise1, promise2, promise3])
  .then(result => {
    console.log("가장 빠른 결과:", result); // 첫 번째 결과 (이미 이행된 상태)
  })
  .catch(error => {
    console.error("가장 빠르게 거부된 Promise:", error);
  });

// Promise.allSettled - 모든 Promise가 완료될 때까지 기다린 후 각각의 상태와 결과 반환
Promise.allSettled([promise1, promise2, promise3])
  .then(results => {
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`Promise ${index + 1} 이행:`, result.value);
      } else {
        console.log(`Promise ${index + 1} 거부:`, result.reason);
      }
    });
  });

콜백을 Promise로 변환

레거시 API나 콜백 기반 함수를 Promise로 변환하여 사용할 수 있습니다.

// 콜백 기반 함수를 Promise로 변환
function readFilePromise(filepath) {
  return new Promise((resolve, reject) => {
    fs.readFile(filepath, 'utf8', (err, data) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(data);
    });
  });
}

// 사용 예
readFilePromise('example.txt')
  .then(data => {
    console.log('파일 내용:', data);
  })
  .catch(err => {
    console.error('파일 읽기 오류:', err);
  });

// 타이머를 Promise로 변환
function delay(ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
}

// 사용 예
delay(2000)
  .then(() => {
    console.log('2초 지남');
    return delay(1000);
  })
  .then(() => {
    console.log('추가 1초 지남');
  });

Promise 체이닝으로 콜백 지옥 해결

Promise를 사용하면 중첩된 콜백 대신 체인 형태로 코드를 작성할 수 있습니다.

// 콜백 지옥을 Promise 체인으로 변환
function fetchData(url) {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(`HTTP 오류! 상태: ${response.status}`);
      }
      return response.json();
    });
}

fetchData('https://api.example.com/users')
  .then(users => {
    console.log('사용자 목록:', users);
    return fetchData(`https://api.example.com/users/${users[0].id}/posts`);
  })
  .then(posts => {
    console.log('첫 번째 사용자의 포스트:', posts);
    return fetchData(`https://api.example.com/posts/${posts[0].id}/comments`);
  })
  .then(comments => {
    console.log('첫 번째 포스트의 댓글:', comments);
  })
  .catch(error => {
    console.error('에러 발생:', error);
  });

'Web Development > JavaScript' 카테고리의 다른 글

실전 비동기 프로그래밍 패턴  (0) 2025.03.30
async/await  (0) 2025.03.30
콜백 함수  (0) 2025.03.30
비동기 프로그래밍  (0) 2025.03.30
실전 DOM 조작 예제  (0) 2025.03.30