티스토리 뷰
Promise 등장 배경
- 자바스크립트에서 비동기 처리를 위해서 전통적으로 콜백 함수를 사용하였다.
- 함수 내부에서 함수 호출을 통해 비동기 작업의 결과를 받아서 인자로 주면 이를 이용해 후속 처리 작업을 수행하는 것이다.
- 콜백 함수는 중첩될 수록 가독성이 떨어지고 코드의 흐름을 파악하기 어려워진다는 문제가 있는데 특히 여러 개의 비동기 작업을 수행해야 할 때는 이른바 콜백 지옥(callback hell) 현상이 발생하게 된다.
function increaseAndPrint(n, callback) {
setTimeout(() => {
const increased = n + 1;
console.log(increased);
if (callback) {
callback(increased); // 콜백함수 호출
}
}, 1000);
}
increaseAndPrint(0, n => {
increaseAndPrint(n, n => {
increaseAndPrint(n, n => {
increaseAndPrint(n, n => {
increaseAndPrint(n, n => {
console.log('끝!');
});
});
});
});
});
프로미스로 개선된 비동기 처리
- 자바스크립트의 Promise 객체를 이용하면 콜백 함수에서 들여쓰는 부분을 .then() 으로 표현해 체이닝 할 수 있기 때문에 훨씬 가독성있게 코드를 작성할 수 있다.
function increaseAndPrint(n) {
return new Promise((resolve, reject)=>{
setTimeout(() => {
const increased = n + 1;
console.log(increased);
resolve(increased);
}, 1000)
})
}
increaseAndPrint(0)
.then((n) => increaseAndPrint(n))
.then((n) => increaseAndPrint(n))
.then((n) => increaseAndPrint(n))
.then((n) => increaseAndPrint(n));
Promise 객체
- 프로미스는 비동기 작업의 완료 또는 실패를 나타내는 객체이다. 비동기 작업이 끝날 때까지 결과를 기다리는 것이 아니라 결과를 제공하겠다는 '약속'을 반환한다는 의미에서 Primise라 명명되었다고 한다!
객체 생성
- new 키워드와 함께 Promise 생성자 함수를 사용한다.
- 생성자 안에 두 개의 매개변수를 가진 콜백 함수를 넣게 되는데
- 첫 번째 인수는 작업이 성공했을 때(resolve), 두 번째 인수는 작업이 실패했을 때(reject)를 알려주는 객체이다.
const myPromise = new Promise((resolve, reject) => {
// 비동기 작업 수행
const data = fetch('서버로부터 요청할 URL');
if(data)
resolve(data);
else
reject("Error");
})
객체 처리
- Promise 객체는 비동기 작업이 완료된 이후 후속 작업을 연결시켜 처리할 수 있다.
- 작업이 성공하여 resolve() 를 호출하게 되면 .then으로 이어지고 resolve() 함수의 매개변수의 값이 .then 메소드의 콜백 함수 인자로 들어가서 .then 메소드 내부에서 그 값을 다룰 수 있게 된다.
- 반대로 처리가 실패하면 reject() 가 호출되어 .catch()로 이어지게 된다.
myPromise
.then((value) => { // 성공적으로 수행했을 때 실행될 코드
console.log("Data: ", value);
})
.catch((error) => { // 실패했을 때 실행될 코드
console.error(error);
})
.finally(() => { // 성공하든 실패하든 무조건 실행될 코드
})
Promise 함수 등록
- 위와 같이 프로미스 객체를 변수에 바로 할당하는 방식을 사용할 수도 있지만 보통은 별도로 함수로 감싸서 사용하는 것이 일반적이라고 한다.
// 프로미스 객체를 반환하는 함수 생성
function myPromise() {
return new Promise((resolve, reject) => {
if (/* 성공 조건 */) {
resolve(/* 결과 값 */);
} else {
reject(/* 에러 값 */);
}
});
}
// 프로미스 객체를 반환하는 함수 사용
myPromise()
.then((result) => {
// 성공 시 실행할 콜백 함수
})
.catch((error) => {
// 실패 시 실행할 콜백 함수
});
- 프로미스 객체를 함수로 만들면 다음과 같은 장점이 있다.
- 재사용성 : 함수로 만들어서 필요할 때마다 호출함으로써 반복되는 비동기 작업에 재사용
- 가독성 : 비동기 작업의 정의와 사용을 분리함으로써 코드의 구조를 명확하게 파악 가능
- 확장성 : 여러 개의 프로미스 객체를 반환하는 함수들을 연결하여 복잡한 비동기 로직을 구현 가능
Promise의 상태
Pending(대기) : 처리 진행중
- 프로미스 객체를 생성하고 resolve()나 reject() 메소드를 실행하기 전 대기 상태를 의미한다.
Fulfilled(이행) : 처리 완료
- resolve() 메소드가 실행되면서 비동기 처리 로직이 성공적으로 완료된 상태
- 이행 상태가 된 프로미스 객체는 바로 체이닝 된 .then() 메소드를 호출하여 처리 결과 값을 받을 수 있게 된다.
promise
.then((data) => {
console.log("처리 성공")
})
Rejected(거부) : 처리 실패
- reject() 메소드가 실행되면서 비동기 처리 로직이 실패한 상태
- 실패 상태가 된 프로미스 객체는 바로 체이닝 된 .catch() 메소드를 호출한다.
promise
.catch((error) => {
console.log(error);
console.log("처리 실패 ㅠㅠ")
})
프로미스 체이닝
- 프로미스 체이닝이란, 프로미스 핸들러를 연달아 연결해서 여러 개의 비동기 작업을 순차적으로 수행하는 것이다.
- 체이닝이 가능한 이유는 .then 핸들러에서 반환하는 값 또한 프로미스 객체이기 때문이다.
function plus() {
return new Promise((resolve, reject) => {
resolve(100)
});
}
plus()
.then((value1) => {
const data1 = value1 + 50;
return data1
})
.then((value2) => {
const data2 = value2 + 50;
return data2
})
.then((value3) => {
const data3 = value3 + 50;
return data3
})
.then((value4) => {
console.log(value4); // 250 출력
})
프로미스 정적 메소드
- 프로미스 객체를 생성 & 초기화하지 않고 바로 사용할 수 있는 메소드가 있다.
Promise.resolve(), Promise.reject()
- 원래 resolve(), reject() 메소드는 프로미스 객체를 생성하면서 그 안의 콜백 함수의 매개변수를 통해 호출하여 사용한다.
// 프로미스 생성자를 사용하여 프로미스 객체를 반환하는 함수
function getPromiseNumber() {
return new Promise((resolve, reject) => {
const num = Math.floor(Math.random() * 10); // 0 ~ 9 사이의 정수
resolve(num); // 프로미스 이행
});
}
- 이러한 과정을 객체 생성 없이 호출하여 사용할 수 있도록 하는 메소드이다.
- 프로미스 객체와 전혀 연관이 없는 함수에서 필요에 따라 프로미스 객체를 반환해 핸들러로 이용할 수 있다.
// 프로미스 객체와 전혀 연관없는 함수
function getRandomNumber() {
const num = Math.floor(Math.random() * 10); // 0 ~ 9 사이의 정수
return num;
}
// Promise.resolve() 를 사용하여 프로미스 객체를 반환하는 함수
function getPromiseNumber() {
const num = getRandomNumber(); // 일반 값
return Promise.resolve(num); // 프로미스 객체
}
// 핸들러를 이용하여 프로미스 객체의 값을 처리하는 함수
getPromiseNumber()
.then((value) => {
console.log(`랜덤 숫자: ${value}`);
})
.catch((error) => {
console.error(error);
});
Promise.all()
- 배열, Map, Set에 포함된 여러 개의 프로미스 요소들을 한꺼번에 비동기 처리할 때 사용된다.
- 모든 비동기 처리가 이행(fulfilled)될 때까지 기다렸다가 한꺼번에 모아서 .then 핸들러를 실행하는 형태로 볼 수 있다.
- 여러 개의 API요청을 보내고 모든 응답을 받아서 한 번에 처리해야 하는 경우에 사용될 수 있다.
// 1. 서버 요청 API 프로미스 객체 생성 (fetch)
const api_1 = fetch("요청 URL 1");
const api_2 = fetch("요청 URL 2");
const api_3 = fetch("요청 URL 3");
// 2. 프로미스 객체들을 묶어 배열로 구성
const promises = [api_1, api_2, api_3];
// 3. Promise.all() 메서드 인자로 프로미스 배열을 넣어, 모든 프로미스가 이행될 때까지 기다리고, 결과값을 출력
Promise.all(promises)
.then((results) => {
// results는 이행된 프로미스들의 값들을 담은 배열.
// results의 순서는 promises의 순서와 일치.
console.log(results); // [users1, users2, users3]
})
.catch((error) => {
// 어느 하나라도 프로미스가 거부되면 오류를 출력
console.error(error);
});
Promise.allSettled()
- Promise.all() 과 역할은 비슷하지만 Promise.all()이 프로미스 중 하나라도 reject 되면 오류를 출력하는 것과 달리, 모든 프로미스 각각의 상태와 값을 모아놓은 배열을 반환한다.
// 1초 후에 1을 반환하는 프로미스
const p1 = new Promise(resolve => setTimeout(() => resolve(1), 1000));
// 2초 후에 에러를 발생시키는 프로미스
const p2 = new Promise((resolve, reject) => setTimeout(() => reject(new Error('error')), 2000));
// 3초 후에 3을 반환하는 프로미스
const p3 = new Promise(resolve => setTimeout(() => resolve(3), 3000));
// 세 개의 프로미스의 상태와 값 또는 사유를 출력
Promise.allSettled([p1, p2, p3])
.then(result => console.log(result));
Promise.any(), Promise.race()
- Promise.all()이 모든 프로미스가 완료되어야만 결과를 반환한다면, Promise.any()는 주어진 프로미스 중 하나라도 완료되면 가장 먼저 완료된 프로미스 하나만 반환한다.
- 그리고 Promise.any()는 가장 먼저 이행(fulfilled) 상태가 된 프로미스를 반환한다면 Promise.race() 는 이행, 실패 여부 상관없이 가장 먼저 처리가 끝난 프로미스 결과값을 반환한다.
참고 자료
반응형
'개발냥이 > 자바스크립트(Javascript)' 카테고리의 다른 글
[자바스크립트] 패키지 매니저 정리(npm, yarn, yarn berry, pnpm) (1) | 2023.06.13 |
---|---|
[자바스크립트] 비동기 통신_async/await (0) | 2023.05.02 |
[React] 리덕스(Redux) 이해하기 (0) | 2023.04.24 |
[자바스크립트] 동기와 비동기(feat. 콜백 함수) (0) | 2023.04.18 |
[JavaScript] 프로토타입(Prototype) (0) | 2023.03.15 |
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 자바bfs
- BFS
- 정렬
- 프로그래머스
- 리액트
- java
- 자바트리
- DP
- Nest
- 알고리즘
- 이분탐색
- dfs
- 형변환
- JavaScript
- SQL
- Spring
- Algorithm
- Comparator
- Queue
- 스프링부트
- 스프링
- 자바스크립트
- 자바
- JPA
- CS
- 백준
- 타입스크립트
- 자바dp
- 해시맵
- SQLD
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함