promise
promise : 비동기 처리에 사용되는 자바스크립트 객체, state(상태)와 result(결과물) 두 속성을 가진다
비동기 작업이 맞이할 성공 혹은 실패를 나타냄
비동기 작업이 진행중일 때는 비어있다가, 작업이 완료되면 그 작업에 대한 결과물로 promise 상자가 채워진다
= 비동기 작업의 상태(성공 혹은 실패)를 나타내는 상자
promise 상자에 붙은 딱지가 state, 상자 안에 들어가는 결과물이 result이다
promise의 3가지 상태 (Pending, Fulfilled, Rejected)
1. Pending - 대기
Pending state : 비동기 작업이 진행중일때 객체는 pending state를 갖고있음 작업이 아직 성공하지도, 실패하지도 않은 대기상태기 때문. 이때 promise의 result는 undefined가 된다
2. Fulfilled - 성공
비동기 작업이 성공적으로 완료되면, 객체는 fulfilled state를 가짐 이때 promise의 result는 비동기 작업이 반환한 결괏값이 된다. 성공 딱지가 붙은 promise 상자 안에 결괏값이 들어있음
비동기 작업이 진행되다가 문제가 발생해서 실패하게 된다면, promise는 rejected state를 가짐
비동기 작업이 실패하면, promise의 result로는 error 객체가 들어가고, 이 error를 보고 실패 이유를 알 수 있다
현재 promise 객체가 가지고 있는 state에 따라 result가 달라지게 된다
new 를 사용해서 promise 상자를 만들 수 있다
promise의 생성자는 함수를 하나 전달 받는 데, 이 함수를 ' executor 함수'라고 하고, 이 안에 우리가 원하는 비동기 작업을 처리해주면 된다
executor 함수는 resolve와 reject라는 두 가지 인자를 전달받는데, 이는 promise가 자체적으로 전달해 주는 것들임
const promise = new Promise(
(resolve,
(reject) => {
console.log('비동기 작업');
})
);
// 출력 : 비동기 작업
new 키워드를 사용해 promise 객체가 생성되는 그 즉시 executor 함수가 실행됨
resolve, reject : executor 내부에서 호출할 수 있는 함수. 비동기 작업이 성공하면 resolve, 실패하면 reject를 각각 호출
1) pending state
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const data = { name: '냥이' };
console.log('네트워크 요청 성공');
});
});
console.log(promise);
promise상자에 비유하면 대기 딱지가 붙어있는 텅텅 빈 상자, 아직 promise한테 비동기 작업이 완료됐다는 것을 알려주지 않았기 때문. 이제 1초 후 데이터 받아오는 것이 완료되면 promise에게 작업이 완료됐음을 알려야 하는데, 이 때 resolve를 사용한다
2) fulfilled state
resolve의 인자로는 비동기 작업의 결과물을 넣어준다(line 3 의 data)
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const data = { name: '냥이' };
console.log('네트워크 요청 성공');
resolve(data);
}, 1000);
});
setTimeout(() => {
console.log(promise);
}, 2000);
promise상자에 비유하면 성공 딱지가 붙어있는 상자 안에 비동기 작업의 결과물인 data가 들어있는 것이다
3) rejected state
reject의 인자로는 비동기 작업이 왜 실패했는지 알려주는 error 객체를 넣어주는 것이 보편적
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
// const data = { name: '냥이' };
const data = null;
if (data) {
console.log('네트워크 요청 성공');
resolve(data);
} else {
reject(new Error('네트워크 문제!!!'));
}
resolve(data);
}, 1000);
});
setTimeout(() => {
console.log(promise);
}, 2000);
promise상자에 비유하면 실패 딱지가 붙어있는 상자에 error가 들어가 있다고 생각하면 된다
특정 함수가 호출되었을 때 비동기 작업을 만들고자 한다면(비동기 함수) 함수를 하나 만들고 그 안에서 promise를 생성해 주면 된다.
비동기 함수 만들기
function getData() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const data = { name: '냥이' };
// const data = null;
if (data) {
console.log('네트워크 요청 성공');
resolve(data);
} else {
reject(new Error('네트워크 문제!!!'));
}
resolve(data);
}, 1000);
});
return promise;
}
const promise = getData();
setTimeout(() => {
console.log(promise);
}, 2000);
promise를 리턴하는 이유 : getData함수를 호출하는 입장에서 비동기 작업이 어떻게 진행되고 있는지 알아야 하기 때문
Promise를 반환(리턴)하는 비동기 함수 사용하기
비동기 함수를 의미있게 사용하기 위해서는 비동기 작업이 다 끝날때까지 기다릴 수 있어야 한다. 그리고 만약
비동기 작업이 성공적으로 완료됐다면, 그에 따른 처리를 할 수 있어야 하고, 실패했다면 적절한 에러 처리를 할 수 있어야 한다. 이 모든것들을 비동기 함수로부터 전달받은 promise를 객체를 통해 간편하게 할 수 있다
then(), catch(), finally() : promise 객체가 제공하는 API, 비동기 작업에 대한 후처리를 간편하게 할 수 있음
1) then() : 비동기 작업이 성공할 경우
then() : 콜백함수를 전달받음, then() 내부에 비동기 작업에 대한 후처리를 한다
function getData() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const data = { name: '냥이' };
// const data = null;
if (data) {
console.log('네트워크 요청 성공');
resolve(data);
} else {
reject(new Error('네트워크 문제!!!'));
}
resolve(data);
}, 1000);
});
return promise;
}
//then()
const promise = getData();
promise.then(() => {
console.log('완료!');
});
비동기 작업이 완료되고 나서 then 내부에 있는 콜백함수가 실행된 것을 확인할 수 있다
이처럼 then은 비동기작업이 완료될때까지 기다리다가 promise가 fulfilled 상태로 바뀌면 then 내부의 콜백함수를 호출한다
이때 콜백함수는 매개변수를 하나 전달받는데, 이 매개변수는 promise의 result를 담고 있다
.
.
.
//then()
const promise = getData();
promise.then((data) => {
console.log(data);
});
우리가 전달해준 name 객체가 출력된 걸 확인할 수 있다
promise 변수를 지워주고 getData() 뒤에 바로 then을 붙이면 더욱 간단해진다
.
.
.
//then()
getData().then((data) => {
const name = data.name;
console.log(`${name}님, 안녕하세요`);
});
2) catch() : 비동기 작업이 실패할 경우
promise의 state는 rejected가 되고, result는 error로 채워진다.
error에 대한 후처리는 catch()를 사용하고, catch도 콜백함수를 전달받는다
=> 비동기 작업을 처리하다가 중간에 문제 발생해 promise가 실패하면 catch내부의 콜백함수가 실행된다
이 콜백함수의 인자에는 (rejected 안에 전달해준)error가 들어간다
function getData() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
// const data = { name: '냥이' };
const data = null;
if (data) {
console.log('네트워크 요청 성공');
resolve(data);
} else {
reject(new Error('네트워크 문제!!!'));
}
resolve(data);
}, 1000);
});
return promise;
}
//catch()
getData()
.then((data) => {
const name = data.name;
console.log(`${name}님, 안녕하세요`);
})
.catch((error) => {
console.log(error);
});
.
.
.
.catch((error) => {
console.log('멋진 에러');
});
에러가 잘 발생한 것을 확인할 수 있다
3) finally()
finally() : promise의 성패 여부와 관련 없이 무조건 수행되어야 하는 코드가 있을 때 사용
finally 내부에 콜백함수를 전달해주면 이 콜백함수는 promise의 성공 여부와는 상관 없이 제일 마지막에 호출됨
.
.
.
//finally()
getData()
.then((data) => {
const name = data.name;
console.log(`${name}님, 안녕하세요`);
})
.catch((error) => {
console.log('멋진 에러');
})
.finally(() => {
console.log('마무리 작업');
});
Promise Chaining
promise의 then은 항상 새로운 promise를 리턴해줌 따라서 then 뒤에 또 다른 then을 연결할 수 있다
이렇게 체인 형태로 연결하는 기법을 Promise Chaining이라고 하고, 이 기법을 사용하면 여러개의 비동기 작업을 순서대로 수행할 수 있다
const promise = getData();
promise.then().then().then()//...
promise chaining을 사용하면 여러개의 비동기 함수를 순차적으로 수행해야 될 때 코드를 깔끔하게 사용할 수 있다.
function getData() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const data = { name: '냥이' };
// const data = null;
if (data) {
console.log('네트워크 요청 성공');
resolve(data);
} else {
reject(new Error('네트워크 문제!!!'));
}
resolve(data);
}, 1000);
});
return promise;
}
//promise chaining
const promise = getData();
promise
.then((data) => {
console.log(data);
return getData(); //promise를 리턴
})
.then((data) => {
console.log(data);
// 첫번째 then 안에서 반환된 promise가
// resolve될 때까지 기다렸다가
// 다음에 오는 then 블록이 실행됨
});
.
.
.
//promise chaining
const promise = getData();
promise
.then((data) => {
console.log(data);
return getData(); //promise를 리턴
})
.then((data) => {
console.log(data);
return getData();
})
.then((data) => {
console.log(data);
});
console.log를 다 지우고 문법도 생략해보면 훨씬 깔끔해진다
.
.
.
//promise chaining
const promise = getData();
promise
.then((data) => getData())
.then((data) => getData())
.then((data) => getData())
.then(console.log);
비동기 콜백과 콜백 체이닝을 비교했을때, promise를 통해 작성한 코드가 훨씬 더 가독성이 높다
이처럼 promise chaining을 사용하면, 각 비동기 작업을 then으로 연결시켜 순차적으로 수행할 수 있기 때문에
더 이상 콜백함수를 중첩할 필요가 없게 된다(콜백 지옥 해결!)
//promise chaining
const promise = getData();
promise
.then((data) => getData())
.then((data) => getData())
.then((data) => getData())
.then(console.log);
//비동기 콜백
getData((data)=>{
getData((data)=>{
getData((data)=>{
// ...
})
})
})
return값에 promise가 아닌 특정 값을 리턴해주면 어떻게 될까?
'
'
'
//promise chaining
const promise = getData();
promise.then((data) => {
console.log(data);
return 'hello';
});
문자열 값을 리턴해줘도 then은 항상 promise를 리턴해준다
이렇게 리턴된 값(hello)은 promise로 감싸져서 곧바로 resolve가 된 상태가 되고, 그 다음에 오는 then으로 넘겨준다
=> 따라서 promise가 resolve될때까지 기다릴 필요 없이 즉시 사용 가능
.
.
.
//promise chaining
const promise = getData();
promise
.then((data) => {
console.log(data);
return 'hello';
})
.then((data) => {
console.log(data);
});
https://www.youtube.com/watch?v=mYHVOTxEwlY&t=811s
'Front-end > JavaScript' 카테고리의 다른 글
[JavaScript - 비동기 시리즈 4] Async & Await (0) | 2025.03.23 |
---|---|
[JavaScript - 비동기 시리즈 2] 비동기 Callback (0) | 2025.03.23 |
[JavaScript - 비동기 시리즈 1] 동기 VS 비동기 (0) | 2025.03.22 |
[JavaScript] Callback 함수 (0) | 2025.03.22 |
[JavaScript] this와 bind (0) | 2025.03.19 |
댓글