본문 바로가기

Promise와 비동기 프로그래밍: 비동기 코드의 이해

에온르 2024. 5. 4.
반응형

자바스크립트는 단일 스레드 기반의 언어로, 비동기 프로그래밍은 자바스크립트에서 매우 중요한 부분입니다. Promise 객체는 비동기 작업을 더욱 효율적으로 다루기 위해 도입되었습니다. 이 강의에서는 Promise의 기본과 비동기 프로그래밍 기법에 대해 알아보겠습니다.

source by freecodecamp.org


비동기 프로그래밍의 필요성

자바스크립트에서 비동기 프로그래밍이 필요한 이유는 무엇일까요? 주로 웹에서 발생하는 다음과 같은 시나리오에서 필요합니다:

  • 서버로부터 데이터를 요청하고 받아오는 작업
  • 파일 I/O 작업
  • 타이머를 사용한 작업

이러한 작업들을 동기적으로 처리하게 되면, 요청이 완료될 때까지 애플리케이션의 실행이 멈추어 사용자 경험에 악영향을 미칠 수 있습니다.


Promise의 이해

Promise는 비동기 작업의 최종 완료(또는 실패) 및 그 결과값을 나타냅니다. Promise 객체는 다음 세 가지 상태 중 하나를 가질 수 있습니다:

  • Pending(대기): 아직 결과가 없는 상태
  • Fulfilled(이행): 작업이 성공적으로 완료됨
  • Rejected(거부): 작업이 실패함

Promise 생성

Promise를 생성할 때는 new Promise() 생성자를 사용하며, 이 생성자는 실행 함수를 인자로 받습니다. 이 함수는 resolve와 reject라는 두 개의 매개변수를 가집니다.

let myPromise = new Promise(function(resolve, reject) {
    // 비동기 작업을 수행합니다.
    if (/* 작업 성공 */) {
        resolve("Success!");
    } else {
        reject("Error!");
    }
});

Promise 사용

Promise가 반환된 후, .then() 메서드를 사용하여 이행 상태의 결과를 처리할 수 있고, .catch() 메서드를 사용하여 거부 상태의 결과를 처리할 수 있습니다.

myPromise
    .then(function(value) {
        console.log(value); // 성공: "Success!"
    })
    .catch(function(error) {
        console.log(error); // 실패: "Error!"
    });

비동기 프로그래밍의 실제 적용

AJAX 요청과 Promise

웹 애플리케이션에서 서버로부터 데이터를 받아오는 경우, AJAX 요청을 비동기적으로 처리하는 것이 일반적입니다. fetch() API는 내부적으로 Promise를 사용하여 HTTP 요청을 비동기적으로 처리합니다.

fetch('https://api.example.com/data')
    .then(response => response.json())  // 응답을 JSON으로 변환
    .then(data => console.log(data))
    .catch(error => console.error('Failed to retrieve data:', error));

고급 비동기 패턴

async/await 사용

ES2017에서 도입된 async와 await 키워드는 Promise를 더욱 쉽게 사용할 수 있게 해 줍니다. async 함수는 항상 Promise를 반환하며, await 키워드는 Promise가 해결될 때까지 함수의 실행을 일시 중단하고, Promise의 결과값으로 재개합니다.

async function fetchData(url) {
    try {
        const response = await fetch(url);
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Failed to fetch data:', error);
    }
}
fetchData('https://api.example.com/data');

Promise.all

여러 비동기 작업을 동시에 처리해야 할 때, Promise.all을 사용하면 모든 Promise 객체가 이행될 때까지 기다린 다음, 결과를 배열로 반환합니다. 하나라도 거부되면 즉시 거부합니다.

Promise.all([
    fetch('https://api.example.com/data1'),
    fetch('https://api.example.com/data2')
]).then(responses => {
    return Promise.all(responses.map(r => r.json()));
}).then(data => {
    console.log('Data 1:', data[0]);
    console.log('Data 2:', data[1]);
}).catch(error => {
    console.error('Error fetching one or more resources:', error);
});

Promise.race

Promise.race는 여러 Promise 중 가장 먼저 이행되거나 거부된 Promise의 결과로 Promise를 해결합니다. 이는 타임아웃을 구현할 때 유용하게 사용됩니다.

const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('Request timed out')), 5000));
const fetchPromise = fetch('https://api.example.com/data');

Promise.race([fetchPromise, timeout])
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error('Failed:', error));

실습 예제: 비동기 태스크 시뮬레이션

비동기 프로그래밍의 이해를 돕기 위해 간단한 비동기 태스크 실행 예제를 살펴봅시다. 아래의 코드는 비동기로 여러 태스크를 처리하는 방법을 시뮬레이션합니다.

async function simulateAsyncTask(name, delay) {
    return new Promise(resolve => setTimeout(() => {
        console.log(`${name} task done!`);
        resolve();
    }, delay));
}

async function performTasks() {
    await simulateAsyncTask('First', 2000); // 2초 후 완료
    await simulateAsyncTask('Second', 1000); // 1초 후 완료
    console.log('All tasks completed!');
}

performTasks();

결론

비동기 프로그래밍과 Promise는 자바스크립트에서 중요한 개념들입니다. 이를 이해하고 적절히 활용함으로써, 복잡한 웹 애플리케이션에서도 효과적으로 데이터를 처리하고 사용자 경험을 최적화할 수 있습니다. 현대 웹 개발에서는 이러한 기술을 능숙하게 다룰 수 있는 능력이 요구됩니다.

반응형

댓글