⌨
Promise
March 09, 2022
Promise란?
- Promise는 비동기 동작을 처리하기 위해 ES6에 도입되었다.
- Promise는 클래스이고, Promise 클래스를 인스턴스화 해서 promise 객체를 만든다.
- 반환된 promise로 원하는 비동기 동작을 처리한다.
- Promise는
state
와resolve
,reject
함수를 이해해야 된다.
Promise 기본 형태 구현하기
let promise = new Promise(function (resolve, reject) {
// 여기 비동기 로직을 작성!
// 시켜놓고 언제 완료될지 모르는 로직!
// 완료 하면 -> resolve 호출
// 비동기 동작 실패 하면 -> reject 호출
});
promise.then(function () {
// 이 함수가 바로 위의 resolve 입니다.
// 위의 비동기 로직이 성공하면 호출 됩니다!
});
let promise = new Promise(function(resolve, **reject**) {
});
// then 인자 둘 다 cb 함수
// 첫 번째는 성공했을 때 실행할 resolve 함수 정의
// 두 번째는 실패했을 때 실행할 reject 함수 정의
promise.then(function() {}, **function() {}**);
promise 3가지 상태(State)
Pending(대기)
- 비동기 처리 로직이 아직 완료되지 않은 상태
Fulfilled(이행)
- 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
Rejected(실패)
- 비동기 처리가 실패하거나 오류가 발생한 상태
let promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('before', promise);
resolve(1);
console.log('after', promise);
}, 1000);
});
promise.then(function (data) {
console.log(data);
});
// 출력 결과
// before Promise {<pending>}
// after Promise {<fulfilled: 1>}
// 1
let promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('before', promise);
reject(1);
console.log('after', promise);
}, 1000);
});
promise.then(
function (data) {
console.log('resolve', data);
},
function (data) {
console.log('reject', data);
},
);
// 출력 결과
// before Promise {<pending>}
// after Promise {<rejected>: 1}
// reject 1
resolve, reject 이해하기
resolve
- 비동기 로직이 성공했을 때 실행할 함수
reject
- 비동기 로직이 실패했을 때 실행할 함수
let promise = new Promise(function(**resolve**, reject) {
setTimeout(function() {
// resolve 함수에 인자 넘기면
**resolve('hello world');**
}, 2000);
});
// resolve 호출시 전달되는 인자 → then 콜백함수의 매개변수로 받는다.
promise.then(**function(msg) {
console.log(msg); // 2초 뒤에 hello world!
}**);
- resolve 호출시 전달되는 인자 → then 콜백함수의 매개변수로 받는다.
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
// 실패한 건 아니지만, 실패했다고 가정하고 reject 호출
// 보통은 api를 호출하고 응답 에러가 났을 때 reject를 호출하죠.
**reject('으악!');**
}, 2000);
});
promise.then(function() {
console.log('resolve'); // 여기는 실행이 안 되고
}, **function(msg) {
console.log('reject', msg); // 여기만 실행됨! "reject 으악!"
}**);
에러 처리 - reject
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
reject('으악!');
}, 2000);
});
promise.then(function() {}, **function(msg) {**
console.log(msg);
**}**);
- 두 번째 인자로 에러처리 로직을 작성하시거나, 아래와 같이 catch함수를 사용할 수 있습니다.
에러 처리 - catch
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
reject('으악!');
}, 2000);
});
promise
.then(function() {})
.catch(**function(err) {
console.log(err);
}**);
- catch로 받는 것이 가독성이 더 좋습니다.
- reject handler와 catch 방식은 똑같습니다.
resolve, reject 주의하기!
let promise = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(1); // 첫 번째 resolve 만 실행됨
resolve(2);
}, 1000);
});
promise.then(function (msg) {
console.log(msg);
});
let promise = new Promise(function (resolve, reject) {
setTimeout(function () {
reject(1); // 첫 번째 reject 만 실행됨
resolve(2);
resolve(3);
}, 1000);
});
promise.then(
function (msg) {
console.log('resolve', msg);
},
function (msg) {
console.log('reject', msg);
},
);
Promise Chaining
- 여러 개의 비동기 작업을 순차적으로 해야하는 경우가 많다.
- 순차적으로 각각의 작업이 이전 단계 비동기 작업이 성공하고 나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우
getProducts() // 상품 가져오고
.then(getComments) // 그리고 후기 가져오고
.then(getLikes); // 그리고 좋아요 가져오고
then의 cb의 반환 값
- 값의 반환
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 1000);
});
promise
.then(function(first) {
console.log('first', first);
return **2**;
}).then(function(**second**) {
console.log(second);
});
// 출력 결과
// first 1
// 2
- promise 반환
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(1);
}, 1000);
});
promise
.then(function(first) {
console.log('first', first);
return 2;
})
.then(function(second) {
console.log('second', second);
return new Promise(function(resolve, reject) {
setTimeout(function() {
**resolve(3);**
}, 1000);
});
})
.then(**function(third) {
console.log('third', third);
}**);
// 출력 결과
// first 1
// second 2
// third 3
Promise.all()
-
여러 프로미스를 모두 성공시킨 후, 완료 로직을 실행하고 싶은 경우 사용
Promise.all([ new Promise((resolve) => setTimeout(() => resolve(1), 9000)), // 1 new Promise((resolve) => setTimeout(() => resolve(2), 2000)), // 2 new Promise((resolve) => setTimeout(() => resolve(3), 1000)), // 3 ]).then(function (value) { console.log(value); });
- 9초 뒤에 value의 값이 [1, 2, 3] 으로 들어옵니다.
let urls = [ 'https://api.github.com/users/iliakan', 'https://api.github.com/users/remy', 'https://api.github.com/users/jeresig', ]; // map every url to the promise of the fetch let requests = urls.map((url) => fetch(url)); // Promise.all waits until all jobs are resolved Promise.all(requests).then((responses) => responses.forEach((response) => alert(`${response.url}: ${response.status}`)), );
async & await
- async function은 ES8에 도입되었으며, 비동기 함수를 선언합니다.
- async function은 promise를 반환하기 때문에 Promise를 잘 알아야 한다.
- await를 쓰려면 async 함수 안에 꼭 있어야 한다.
Quiz
let promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(1);
resolve(2);
console.log(3);
resolve(4);
}, 1000);
});
promise.then(function (data) {
console.log(data);
});
// 출력 결과
// 1
// 3
// 2
let promise = new Promise(function (resolve, reject) {
resolve(1);
setTimeout(function () {
resolve(2);
}, 1000);
});
promise.then(function (data) {
console.log(data);
});
// 출력 결과
// 1
$.get('https://api.test.com/proudcts', function (response) {
var firstProductId = response.products[0].id;
$.get('https://api.test.com/proudct/comments?id=' + firstProductId, function (response) {
var firstCommentId = response.comments[0].id;
$.get('https://api.test.com/proudct/comment/likes?id=' + firstCommentId, function (response) {
var likes = response.likes;
var likesCount = likes.length;
// 첫번째 상품의 -> 첫번째 후기의 좋아요 수 화면에 적용!
});
});
});
// Promise 형태로 바꾸기
axios('https://api.test.com/proudcts')
.then(function (response) {
let firstProductId = response.products[0].id;
return axios('https://api.test.com/proudct/comments?id=' + firstProductId);
})
.then(function (response) {
let firstCommentId = response.comments[0].id;
return axios('https://api.test.com/proudct/comment/likes?id=' + firstCommentId);
})
.then(function (response) {
let likes = response.likes;
let likesCount = likes.length;
});
// 답
function job() {
return new Promise(function (resolve, reject) {
reject();
});
}
job()
.then(function () {
console.log(1);
})
.then(function () {
console.log(2);
})
.then(function () {
console.log(3);
})
.catch(function () {
console.log(4);
})
.then(function () {
console.log(5);
});
// 출력 결과
// 4
// 5
function job(state) {
return new Promise(function (resolve, reject) {
if (state) {
resolve('success');
} else {
reject('error');
}
});
}
job(true)
.then(function (data) {
console.log(data, 1);
return job(false);
})
.catch(function (error) {
console.log(error, 2);
return 'Error caught';
})
.then(function (data) {
console.log(data, 3);
return job(true);
})
.catch(function (error) {
console.log(error, 4);
});
// 출력 결과
// sucess
// error
// Error caught
마무리
- 사실 IE에서 사용할 수 없다. 😫