Front-End/JavaScript

[JavaScript] Promise 정리 (fetch, async, await, then)

시니철 2024. 9. 21. 17:08

Promise란?

비동기 작업이 완료되면 값을 알려 주는 객체이고, 작업이 완료되면 값을 알려줄 것을 약속하기 때문에 이름이 Promise 입니다.

 

Promise 객체는 세 가지 상태로

Panding : 비동기 작업이 끝나기를 기다릴 때

Fulfilled : 비동기 작업이 성공적으로 끝났을 때, 비동기 작업의 성공 결과 값으로 갖게 됨.

Rejected : 비동기 작업이 실패했을 때, 비동기 작업에서 발생한 오류를 결과 값으로 갖게 됨.

 

Promise 기반의 코드

// Promise 기반
const response = await fetch('...');
const data = await response.json();
console.log(data);

 

평소에 사용하는 코드와 비슷한 모습이며, 비동기 작업을 처리할 때도 우리가 익숙한 형태로 코드를 작성할 수 있다는게 장점이고, 자바스크립트에서 많은 비동기 코드가 Promise를 활용하는 이유입니다.

 

Promise 객체를 다루는 방법은

  1. .then() 메소드 + 콜백
  2. asyncawait 문법

위 두 가지로, 처음 배울 땐 asyncawait 문법이 직관적이고 이해하기 쉬울 수 있습니다.


fetch

fetch는 웹 리퀘스트를 보낼 때 많이 사용하며, 서버로부터 데이터를 받아올 수 있습니다.

const response = fetch('https://hwiiron.com/api/fetch');

console.log(response); // Promise{ <pending> }

임의로 넣은 URL로 실제로는 동작하지 않습니다.

 

위 코드는 fetch 함수가 반환하는 Promise 객체를 response에 저장하는 것입니다. fetch는 비동기적으로 동작하므로, 데이터를 즉시 반환하지 않고 Promise가 대기(pending) 상태로 나타납니다.

 

데이터를 실제로 사용하려면 async / await이나 .then()을 사용하여 Promise가 완료될 때까지 기다려야 합니다.


await

const response = await fetch('https://hwiiron.com/api/asycnAwait');

console.log(response); // 복잡한 결과 값 출력

 

Promise 객체 앞에 await 키워드를 쓰면 Promise의 상태가 Fulfilled, Rejected가 될 때까지 기다립니다.

  • Fulfilled가 되면 Promise 객체의 결과 값을 리턴합니다.
  • Rejected가 되면 Promise 객체 결과 값(오류)을 throw합니다.

 

await, fetch를 하여 불러온 결과 값은 복잡하기 때문에 분석된 데이터를 얻기 위해서는 불러온 결과 값(response)을 파싱해야 합니다.

const response = await fetch('https://hwiiron.com/api/asycnAwait');
const data = await response.json()

console.log(data);

 

.json() 메소드로 response를 파싱하면 정확한 데이터 값을 출력합니다.

.json() 메소드도 오래 걸리는 작업이므로 await 키워드를 사용하지 않으면 Promise를 리턴합니다.


async

const response = await fetch('https://hwiiron.com/api/asycnAwait');
const data = await response.json()
console.log(data);

console.log('task 2');

console.log('task 3');

// response를 파싱한 데이터
// task 2
// task 3

async 함수 사용하지 않았을 때

위 소스 코드를 출력하면 response를 파싱한 데이터가 먼저 출력되고, 그 뒤에 task 2task 3이 순서대로 출력됩니다.

 

Promiseawait으로 비동기 처리를 하려면 async 함수를 이용해야 합니다.

async function asycnAwait() {
    const response = await fetch('https://hwiiron.com/api/asycnAwait');
    const data = await response.json()
    console.log(data);
}
// async 화살표 함수 활용법
const asyncAwait = async () => {
    const response = await fetch('https://hwiiron.com/api/asycnAwait');
    const data = await response.json()
    console.log(data);
}

 

async, await 활용

async function asycnAwait() {
    const response = await fetch('https://learn.codeit.kr/api/employees');
    const data = await response.json()
    console.log(data);
}

asycnAwait()

console.log('task 2');

console.log('task 3');

// task 2
// task 3
// response를 파싱한 데이터

 

async 함수 안에서 await을 사용하면 PromiseFulfilled가 될 때까지 기다리는 동안, 함수 밖의 코드를 실행하고, PromiseFulfilled 상태가 되면 다시 함수로 돌아와서 코드를 이어서 실행합니다.

 

async 함수의 리턴값

async function asycnAwait() {
    const response = await fetch('https://learn.codeit.kr/api/employees');
    const data = await response.json()
	return data;
}

const asyncReturn = asycnAwait();

console.log(asyncReturn); // Promise { pending }

 

async 함수는 항상 Promise를 리턴합니다.

  • 함수 안에서 Promise를 리턴하면 그 Promise를 그대로 리턴합니다.
  • 함수 안에서 평범한 값을 리턴하면 그 값을 결과 값으로 갖는 Promise를 리턴합니다.
async function asycnAwait() {
    const response = await fetch('https://learn.codeit.kr/api/employees');
    const data = await response.json()
	return data;
}

const asyncReturn = await asycnAwait();

console.log(asyncReturn);

 

따라서 async 함수에서 리턴하는 값을 가져오려면 await을 활용해야 합니다.

 

동작 순서

  1. async 함수: asycnAwait 함수를 실행하면 pending 상태의 Promise가 즉시 반환됩니다.
  2. 데이터 반환: 함수 내부에서 return data;를 통해 데이터를 반환하면, 해당 데이터가 Promise에 채워지고 Promise의 상태는 Fulfilled로 변경됩니다.
  3. await 키워드: await 키워드를 사용하여 asycnAwait 함수의 실행을 기다리고, 이 결과는 asyncReturn 변수에 할당됩니다. 따라서 async 함수에서 리턴하는 값을 가져오려면 await을 활용해야 합니다.

async와 await 문법에서 try...catch로 오류 처리

fetch는 네트워크가 불안정하거나, 서버에서 오류가 나거나, 잘못된 URL에 리퀘스트를 보내는 다양한 이유로 리퀘스트가 실패할 수 있습니다.

 

Promise기반 코드에서 오류를 처리하려면 try...catch문을 사용하면 됩니다.

async function asycnAwait() {
    try{
        const response = await fetch('https://learn.codeit.kr/api/employees');
        const data = await response.json()
        console.log(data);
    } catch (error) {
    	console.log('Error');
    }
}

console.log('Finished');

 

코드 흐름

  • try블록 안에 코드를 한 줄씩 실행하여 오류가 나지 않으면 마지막 줄까지 실행하고, try...catch문 밖으로 나와서 console.log('Finished');를 출력합니다.
  • try블록 안에서 오류가 나면 오류가 나는 시점에 바로 catch문으로 이동해서 console.log('Error');를 출력하고 try...catch문 밖으로 나와서 console.log('Finished');를 출력합니다.

 

finally문도 함께 사용할 수 있습니다.

async function asycnAwait() {
    try{
        const response = await fetch('https://learn.codeit.kr/api/employees');
        const data = await response.json()
        console.log(data);
    } catch (error) {
    	console.log('Error');
    } finally {
        console.log('Finished');
    }
}

 

trycatch문에서 결과가 어떻든 finally 블록 안의 코드 console.log('Finished');가 실행됩니다.

 

try...catch문 참고

 

[JavaScript] try...catch, finally (throw)

에러와 에러 객체자바스크립트에서는 코드 실행 중 발생할 수 있는 다양한 에러를 처리하기 위해 에러 객체를 사용합니다. `ReferenceError` : 존재하지 않는 변수나 함수를 호출할 때 발생하는 에

hwiiron.tistory.com


.then() 메소드

자바스크립트에서 비동기 코드를 잘 활용하려면 asyncawait, .then() 메소드 둘 다 알고 있는 것이 좋습니다.

 

asyncawait 예시

async function asycnAwait() {
    const response = await fetch('https://hwiiron.com/api/asyncAwait');
    const data = await response.json()
    console.log(data);
}

 

.then() 메소드 예시

const dataPromise = fetch('https://hwiiron.com/api/then')
    .then((response) => response.json())
dataPromise.then((data) => console.log(data));

 

동작 순서

  1. .then()은 Promise 객체의 메소드로, 앞선 비동기 작업이 완료되면 그 결과 값을 처리하는 콜백을 실행합니다.
  2. 첫 번째 .then()에서 response.json()을 호출하여 응답 데이터를 JSON으로 변환 후 Promise를 반환합니다.
  3. 두 번째 .then()은 변환된 데이터를 받아서 출력하는 역할을 합니다.

 

.then() 메소드 간결하게 사용하는 방법

fetch('https://hwiiron.com/api/then')
    .then((response) => response.json())
    .then((data) => console.log(data));
    
console.log('task 2');

console.log('task 3');

 

Promise 체인의 중요한 점은 비동기 작업이 완료되기 전에 다른 코드들이 먼저 실행된다는 것입니다. 그래서 위 코드는 task 2task 3이 먼저 출력된 후, PromiseFulfilled 상태가 되면(비동기 작업이 성공적으로 끝나면) 다음 .then() 메소드의 콜백이 실행되어 성공한 결과 값을 처리하게 됩니다.

 

또한, .then()Promise를 반환하기 때문에 뒤에 바로 또 다른 .then()을 이어서 붙일 수 있고, 이렇게 여러 .then()을 연결하는 방식을 Promise 체인이라고 합니다.


.then() 메소드에서 try...catch로 오류 처리

fetch('https://hwiiron.com/api/then')
    .then((response) => response.json())
    .then((data) => console.log(data))
    .catch((error) => console.log('Error'))
    .finally(() => console.log('Finished));

 

asyncawait 문법에서 try...catch로 오류 처리한 방법과 동일하게 .catch() 메소드는 Promise 체인에서 오류가 발생하면 콜백을 실행해주고, .finally() 메소드는 Promise 체인에서 어떤 일이 발생하든 마지막에 콜백을 실행합니다.


Promise.all() 메소드

Promise.all() 메소드는 여러 개의 Promise 객체를 다룰 때 사용합니다.

 

아규먼트로 전달된 Promise들이 모두 Fulfilled 상태가 되면 PromiseFulfilled 상태가 되고, Promise 중 하나라도 Rejected 상태가 되면 Promise.all()이 리턴하는 PromiseRejected 상태가 됩니다.

async function asycnAwait() {
    const response = await fetch(`https://hwiiron.com/api/asyncAwait/${id}`);
    const data = await response.json()
    console.log(data);
}

const promises = [];

for (let i = 1; i < 11; i++) {
	promises.push(asycnAwait(i));
}

const result = await Promise.all(promises);
console.log(result);

 

동작 순서

  1. asyncAwait 함수는 fetch를 통해 데이터를 가져오고 Promise를 반환합니다.
  2. Promises 배열은 각 Promise 객체를 담고 있으며, Promise.all()은 모든 Promise가 완료될 때까지 기다립니다.
  3. 모든 작업이 완료되면 result에 모든 결과가 배열로 반환됩니다.

Promise 종합 정리

 

Codeit/비동기 자바스크립트/promise/Promise 종합 정리.md at main · hwiiron/Codeit

Codeit Sprint. Contribute to hwiiron/Codeit development by creating an account on GitHub.

github.com