+ Promise& Async/Awai t에 대해 공부한 것을 정리한 것입니다. 배우는 중이라 잘못된 내용이 있을 수 있으며 계속해서 보완해 나갈 것입니다. :))
이전 포스트에서 '비동기 처리 로직을 위해 콜백함수를 연속해서 사용할 때 발생하는 콜백지옥'을 마지막으로 정리해보았다.
콜백 지옥을 해결하기 위해서는 Promise & Async/Await 방식을 사용할 수 있다.
1. Promise
1) Promise란
비동기 처리에 사용할 수 있는 내용이 실행은 되었지만 결과를 아직 반환하지 않은 객체이다.
2) Promise의 필요성
1. callback을 이용한 비동기 함수의 전달 방법
3초 후에 실행되는 어떤 코드를 작성해야한다고 할 때, promise를 사용하지 않았을 때와 사용했을 때의 코드를 비교해보자.
① promise를 사용하지 않는 경우 ( callback을 이용한 비동기 함수의 전달 방법)
function callback(){ /*실행 해야하는 코드 */ }
setTimeout(()=>{callback}, 3000)
이런식으로 콜백함수를 사용해야 할 것이다. 즉, callback이 항상 setTimeout 내에 있어야 해서 밖으로 꺼낼 수 없다.
② promise를 사용한 경우
const promise = setTimeoutPromise(3000)
console.log('딴짓')
console.log('딴짓')
console.log('딴짓')
promise
.then(()=> {
/*실행 해야하는 코드 - 지금 실행해*/
})
이렇게 함수를 분리해서 작성할 수 있다는 것이 promise의 큰 장점 중 하나이다.
2. callback의 중첩
① promise를 사용하지 않는 경우 ( callback을 이용한 비동기 함수의 전달 방법)
function findAndSaveUser(Users){
Users.findOne({}, (err, user) => { //첫 번째 콜백
if(err){
return console.error(err);
}
user.name = 'zero'
user.save((err) => { //두 번째 콜백
if(err){
return console.error(err);
}
Users.findOne({gender: 'm'}, (err, user) => { //세 번째 콜백
//.....
});
//.....
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
이렇게 콜백이 여러개 중첩되어야하는 콜백지옥 상황이 온다.
② promise를 사용한 경우
function findAndSaveUser(Users){
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save()
})
.then((user) => {
return Users.findOne({gender:'m'})
})
.then((user) => {
//.....
})
.catch((err) => {
//
}
})
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
3) Promise의 사용
Promise를 사용하는 비동기 처리 함수는 callback을 사용하지 않고, Promise 객체를 return 한다.
그리고 이 Promise instance는 resolve과 reject를 인자로 가지는 자신만의 callback함수를 실행한다.
const condition = true;
const promise = new Promise((resolve, reject) => {
//4~9번 째 줄까지는 동기로 실행
if(condition){
resolve('성공');
}else{
reject('실패');
}
}); //그리고 이 실행된 결과를 promise가 들고 있다가,
//다른 코드가 들어갈 수 있음
//promise 실행
promise //이렇게 원하는 시점에 .then과 .catch를 통해 사용할 수 있다.
.then((message) => { //성공시
console.log(message);
})
.catch(error) => { //실패시
console.log(error);
}
})
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
- Promise.resolve(성공 리턴값): 바로 resolve 하는 프로미스 => 실행이 완료되면 .then 내부 함수가 실행된다.
- Promise.reject(실패 리턴값): 바로 reject 하는 프로미스 => .catch 내부 함수가 실행된다
- Promise.all(배열) : 여러 개의 프로미스를 동시에 실행하고, 하나라도 실패하면 catch로 간다.
- Promise.allSettled(배열): 실패한 것만 추려낼 수 있다.
ex)
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
Promise.all([promise1, promise2])
.then((result) => {
console.log(result);//['성공1', '성공2']
})
.catch((err) => {
console.error(err);
}
});
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
5) Promise Hell과 Promise Chaining
function gotoCodestates() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('1. go to codestates') }, Math.floor(Math.random() * 100) + 1)
})
}
function sitAndCode() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('2. sit and code') }, Math.floor(Math.random() * 100) + 1)
})
}
function eatLunch() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('3. eat lunch') }, Math.floor(Math.random() * 100) + 1)
})
}
function goToBed() {
return new Promise((resolve, reject) => {
setTimeout(() => { resolve('4. goToBed') }, Math.floor(Math.random() * 100) + 1)
})
}
gotoCodestates()
.then(data => {
sitAndCode()
.then(data => {
eatLunch()
.then(data => {
goToBed()
.then(data => {
console.log(data)
})
})
})
})
이런 코드가 있을 때 Promise 실행 부분을 보면 callback hell에서 봤던것 같은 형태의 Promise hell이 발생하기도 한다. 그래서 적절하게 reeturn을 해줌으로써 Promise chaining으로 여러개의 프로미스를 깔끔하게(?) 연결할 수 있다.
gotoCodestates()
.then(data => {
return sitAndCode()
})
.then(data => {
return eatLunch()
})
.then(data => {
return goToBed()
})
.then(data => {
console.log(data)
})
지금까지 Promise와 사용에 대해서 알아보았다.
그런데 Promise를 사용해도 마지막인 .then .then .then.... 의 반복이고 Callback이든 Promise든 '지옥' 이 존재했다.
Javascript의 비동기 처리 패턴 중 가장 최근에 나온 async & await는 Callback이든 Promise든 '지옥' 단점을 보완할 수도 있고,
비동기 처리 함수들을 마치 동기인 것 처럼 작성할 수 있다.
그래서 바로 위의 코드를 async & await를 사용해서 작성하면,
const result = async () => {
const one = await gotoCodestates();
console.log(one)
const two = await sitAndCode();
console.log(two)
const three = await eatLunch();
console.log(three)
const four = await goToBed();
console.log(four)
}
result();
이렇게 된다.
async & await에 대해서 더 정리해보자.
2. async/await
1) async/await의 사용
앞에서 살펴본 예제에서 async/await을 써 보자.
① promise를 사용한 경우
function findAndSaveUser(Users){
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save()
})
.then((user) => {
return Users.findOne({gender:'m'})
})
.then((user) => {
//.....
})
.catch((err) => {
//
}
})
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
② async/await을 사용한 경우
await literally suspends the function execution until the promise settles, and then resumes it with the promise result
async function findAndSaveUser(Users) {
let user = await Users.findOne({}); //비동기 처리의 결과 값을 user에게 준다.
//await literally suspends the function execution until the promise settles, and then resumes it with the promise result
user.name = 'zero';
user = await user.save();
user = await Users.findOne({gender:'m'});
}
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
즉, async/awiat 역시 promise를 반환하기 때문에 async 함수에서 return 해준 값은 .then이나 await으로 받아야한다.
ex)
async function main(){
const result = await promise;
return 'zerocho';
}
main().then((name) => {
//....
} //이렇게 then으로 받거나 또는
const name = await main()
//이렇게 await으로 받거나!
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
그리고 async 내에서 await을 사용하기도 한다.
2) async/await의 결과 처리
.then 부분은 await을 사용하는데, .catch 부분은 어떻게 처리하는가? try{}, catch{}를 사용한다.
ex)
async function main(){
try{
const result = await promise;
return result;
}
catch(err){ //reject 처리
console.error(err);
}
}
//코드 출처: 제로초 님의 노드교과서 개정판 2-8. Promise, async/await
Reference
'Dev > SW Engineering' 카테고리의 다른 글
16. Interaction With Server - Why We Use Fetch & Let's Use! (0) | 2020.07.21 |
---|---|
15. Interaction With Server - Concepts (0) | 2020.07.21 |
13. Asynchronous & Promise - Asynchronous JS & Callback (0) | 2020.07.21 |
12. Sprint 1/4 Assessment - 중간 점검 (0) | 2020.06.14 |
11. Algorithms - Advanced Brute Force (0) | 2020.06.11 |