코딩 스쿨 JavaScript

언어선택 : HTMLCSSJAVAJAVASCRIPTMYSQLSQL PHP

JavaScript Promises

JavaScript Promises: 개념과 사용법

  • *JavaScript의 프라미스(Promise)**는 비동기 작업을 처리하기 위한 객체로, 성공(fulfilled) 또는 실패(rejected) 상태를 관리하고 그 결과를 비동기적으로 처리할 수 있게 해줍니다. 프라미스는 콜백 함수의 단점인 콜백 헬(Callback Hell) 문제를 해결하며, 가독성유지보수성을 향상시킵니다.

이 가이드는 JavaScript에서 프라미스의 개념실용적인 사용법을 설명합니다.


1. 프라미스(Promise)란?

  • *프라미스(Promise)**는 비동기 작업의 결과를 처리하는 객체입니다. 프라미스는 대기(pending) 상태에서 시작하여, 작업이 완료되면 성공(fulfilled) 또는 실패(rejected) 상태로 변환됩니다. 이후, 성공 시 처리할 작업과 실패 시 처리할 작업을 각각 **then()*과 **catch()*로 정의할 수 있습니다.

1.1. 프라미스의 상태

  • 대기(pending): 프라미스가 완료되지 않은 상태.
  • 이행(fulfilled): 프라미스가 성공적으로 완료된 상태.
  • 거부(rejected): 프라미스가 실패한 상태.

1.2. 프라미스 기본 구조

const myPromise = new Promise((resolve, reject) => {
    // 비동기 작업 수행
    const success = true;  // 작업 성공 여부

    if (success) {
        resolve('Task completed successfully!');
    } else {
        reject('Task failed.');
    }
});

myPromise
    .then((result) => {
        console.log(result);  // 성공 시 실행
    })
    .catch((error) => {
        console.log(error);   // 실패 시 실행
    });

  • resolve(): 프라미스가 성공했을 때 호출되며, **then()*에서 처리됩니다.
  • reject(): 프라미스가 실패했을 때 호출되며, **catch()*에서 처리됩니다.

2. 프라미스 사용 예시

2.1. 비동기 작업 처리 예시

프라미스는 비동기 작업의 결과를 처리하는 데 자주 사용됩니다. 예를 들어, 서버에서 데이터를 가져오는 작업을 프라미스로 처리할 수 있습니다.

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true;

            if (success) {
                resolve('Data fetched successfully.');
            } else {
                reject('Error fetching data.');
            }
        }, 2000);
    });
}

fetchData()
    .then((data) => {
        console.log(data);  // Data fetched successfully. (2초 후 실행)
    })
    .catch((error) => {
        console.log(error);  // Error fetching data.
    });

  • fetchData() 함수는 프라미스를 반환하며, 성공 시 **resolve()*를 호출하고 실패 시 **reject()*를 호출합니다.
  • *then()*과 **catch()*를 사용해 각각 성공실패를 처리할 수 있습니다.

3. 프라미스 체이닝 (Promise Chaining)

  • *프라미스 체이닝(Promise Chaining)**을 사용하면, 여러 비동기 작업순차적으로 처리할 수 있습니다. 각 then() 메서드는 다음 프라미스를 반환할 수 있으며, 이를 통해 작업을 연결할 수 있습니다.

3.1. 프라미스 체이닝 예시

function firstTask() {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log('Task 1 complete');
            resolve('Task 1 result');
        }, 1000);
    });
}

function secondTask(result) {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(`Task 2 complete with ${result}`);
            resolve('Task 2 result');
        }, 1000);
    });
}

firstTask()
    .then((result) => {
        return secondTask(result);
    })
    .then((result) => {
        console.log(`All tasks complete with ${result}`);
    });

  • *firstTask()*와 **secondTask()*는 각각 프라미스를 반환하며, 비동기 작업이 완료된 후 다음 작업을 수행합니다.
  • 프라미스 체이닝을 통해 순차적인 비동기 작업을 쉽게 처리할 수 있습니다.

4. Promise.all(), Promise.race()

4.1. Promise.all()

  • *Promise.all()*은 여러 프라미스가 **모두 이행(fulfilled)**될 때까지 기다린 후, 그 결과를 배열로 반환합니다. 모든 프라미스가 성공해야지만 **then()*이 호출됩니다. 하나라도 **실패(rejected)**하면 **catch()*가 호출됩니다.
const promise1 = new Promise((resolve) => setTimeout(resolve, 1000, 'First'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 2000, 'Second'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 3000, 'Third'));

Promise.all([promise1, promise2, promise3])
    .then((results) => {
        console.log(results);  // ['First', 'Second', 'Third']
    })
    .catch((error) => {
        console.log(error);  // 하나라도 실패하면 호출
    });

  • *Promise.all()*은 모든 프라미스가 성공적으로 완료될 때 결과 배열을 반환합니다.
  • 하나라도 실패하면 **즉시 catch()*로 넘어갑니다.

4.2. Promise.race()

  • *Promise.race()*는 가장 먼저 완료된 프라미스의 결과를 반환합니다. 첫 번째로 **이행(fulfilled)**되거나 **거부(rejected)**된 프라미스가 결과로 반환됩니다.
const fastPromise = new Promise((resolve) => setTimeout(resolve, 1000, 'Fast'));
const slowPromise = new Promise((resolve) => setTimeout(resolve, 3000, 'Slow'));

Promise.race([fastPromise, slowPromise])
    .then((result) => {
        console.log(result);  // 'Fast' (가장 빠른 프라미스가 반환됨)
    })
    .catch((error) => {
        console.log(error);  // 첫 번째 실패한 프라미스가 있으면 에러 처리
    });

  • *Promise.race()*는 가장 먼저 완료된 프라미스의 결과를 반환하며, 그 결과가 성공이든 실패든 상관없이 가장 빠른 프라미스가 처리됩니다.

5. async/await를 사용한 프라미스 처리

  • *async/await*는 프라미스를 더 간결하고 직관적으로 처리할 수 있게 해줍니다. **await*는 프라미스가 완료될 때까지 기다린 후, 그 결과를 반환받습니다.

5.1. async/await 기본 사용법

function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve('Data fetched');
        }, 2000);
    });
}

async function displayData() {
    const data = await fetchData();
    console.log(data);  // 'Data fetched' (2초 후 출력)
}

displayData();

  • async 키워드를 사용해 비동기 함수를 정의하며, 함수 내에서 **await*를 사용해 프라미스가 완료될 때까지 기다립니다.
  • 프라미스 체이닝을 사용하는 것보다 가독성이 훨씬 높아집니다.

5.2. async/await와 오류 처리

  • *async/await*에서도 try...catch 구문을 사용하여 프라미스의 오류 처리를 할 수 있습니다.
async function displayData() {
    try {
        const data = await fetchData();
        console.log(data);
    } catch (error) {
        console.log('Error:', error);  // 에러 처리
    }
}

displayData();

  • try...catch 구문을 통해 프라미스가 실패했을 때 오류를 처리할 수 있습니다.

6. 프라미스의 장점과 단점

6.1. 장점

  • 콜백 헬을 해결하고, 가독성과 **유

지보수성**이 높은 비동기 코드를 작성할 수 있습니다.

  • 프라미스 체이닝을 통해 비동기 작업을 순차적으로 처리할 수 있습니다.
  • *async/await*을 사용하면 더 직관적이고 동기 코드처럼 작성할 수 있습니다.

6.2. 단점

  • 오래된 브라우저에서는 **Promise*와 **async/await*가 지원되지 않을 수 있으며, **폴리필(polyfill)**이 필요할 수 있습니다.
  • 에러 처리가 제대로 이루어지지 않으면 비동기 작업에서 예상치 못한 버그가 발생할 수 있습니다.

요약

  • *JavaScript의 프라미스(Promise)**는 비동기 작업을 관리하는 중요한 객체로, 성공 또는 실패를 처리할 수 있습니다. 프라미스는 콜백 함수의 단점을 해결하고, 비동기 작업을 더 쉽게 관리할 수 있게 해줍니다.
  • *Promise*는 **resolve()*와 **reject()*를 통해 성공실패를 처리하며, **then()*과 **catch()*로 그 결과를 처리합니다.
  • 프라미스 체이닝을 통해 여러 비동기 작업을 순차적으로 처리할 수 있습니다.
  • *Promise.all()*과 **Promise.race()*를 통해 여러 프라미스를 동시에 처리할 수 있습니다.
  • *async/await*를 사용하면 프라미스를 더 직관적이고 간결하게 처리할 수 있으며, 오류 처리도 쉽게 할 수 있습니다.

프라미스는 비동기 프로그래밍에서 중요한 도구이며, 네트워크 요청이나 파일 입출력과 같은 비동기 작업에서 필수적으로 사용됩니다.


copyright ⓒ 스타트코딩 all rights reserved.
이메일 : startcodingim@gamil.com