
이번 공부에서 도움을 받은 강의는 아래의 링크이다.
드림코딩 - 비동기 처리의 시작 콜백 이해하기
드림코딩 - 프로미스 개념부터 활용까지
console.log('1');
setTimeout(function() {
console.log('2');
}, 1000); // 1초뒤에 함수를 call 해줘
console.log('3');
// 결과 1 3 2
간단하게만 말하자면 이 함수를 나중에 call 해줘 = callback 함수
특징은, 굳이 함수 선언문을 작성할 필요 없이 화살표 함수를 일반적으로 많이 사용한다.
setTimeout(() => {
console.log('2');
}, 1000);
콜백 함수를 너무 많이 사용하면 콜백 지옥이 생겨난다.
콜백 지옥은 에러를 잡기도 힘들고, 코드의 가독성을 해친다.
자바스크립트에서 제공하는 비동기를 간편하게 처리할 수 있도록 도와주는 object
정해진 장시간의 기능을 수행하고 나서
promise 에서 주의 깊게 볼 키워드는 두가지이다.
🎯 프로세스가 무거운 작업을 실행하고 있는 중인지, 기능 실행이 성공 / 실패했는지
지정한 작업이 수행중일 때
작업이 성공적으로 완료 되었을 때
파일을 찾을 수 없거나 / 네트워크에 문제가 생겼을 때
producer - 우리가 원하는 데이터를 제공하는 사람consumer - 제공된 데이터를 사용하는 사람🎯 정보를 제공하는 producer와 정보를 소비하는 consumer의 차이점을 알아보자
원하는 기능을 수행해서 해당하는 데이터를 만들어내는 객체
// promise : 우리가 원하는 기능을 비동기적으로 실행하는 클래스 --> new 연산자로 객체 생성 가능
const promise = new Promise((resolve, reject => { // executor 콜백함수 (파라미터 : resolve, reject)
// heavy 한 작업 수행
// 큰 데이터를 읽어오는 과정은 시간이 걸림
// 오래 걸리는 작업을 동기적으로 수행하면 뒤의 작업을 수행하지 못함
// 시간이 걸리는 일은 promise로 만들어서 비동기적으로 실행하는 것이 좋음
// ex) 네트워크, 파일 읽어오기 등
})
resolve - 기능을 정상적으로 실행해서 마지막에 최종 데이터를 전달 하는 콜백 함수reject - 기능 수행 중 문제가 생기면 호출하는 콜백 함수❗️ 새로운 promise가 만들어지면, executor 콜백 함수는 자동적으로 바로 실행된다.
따라서 만약 내가 원하는 순간에 작업을 수행하고 싶다면, 유의해야한다.
// promise : 우리가 원하는 기능을 비동기적으로 실행하는 클래스 --> new 연산자로 객체 생성 가능
const promise = new Promise((resolve, reject => {
console.log('doing something');
setTimeout(() => {
resolve('ellie'); // resolve라는 콜백함수 : 성공적으로 데이터 전달 (네트워크를 받아온 / 파일에서 읽어온)
reejct(new Error('no network'));
}, 2000);
})
우리가 원하는 데이터를 소비하는 객체
then, catch, finally 를 이용하여 값을 받아올 수 있다.
✔️ 값이 정상적으로 수행 될 때 (위의 producer - resolve 와 같이보기)
promise.then((value) => { // promise가 정상적으로 잘 수행 되어서 resolve 콜백함수를 통해 전달한 값이 value라는 파라미터로 전달
console.log(value);
})
✔️ 에러가 발생했을 때 (위의 producer - reject와 같이보기)
promise
.then(value => { // then 호출 --> promise가 리턴
console.log(value);
});
.catch(error => { // 리턴된 promise의 catch 등록
console.log(error);
});
// ex : arr.split('').join 처럼
✔️ 성공 / 실패 여부와 상관없이 어떤 기능을 마지막으로 수행하고 싶을때
promise
.then(value => {
console.log(value);
});
.catch(error => {
console.log(error);
});
.finally(() => {
console.log('finally') // 성공하든 실패하든 어떤 기능을 마지막으로 수행하고 싶을 때
});
then을 사용하여 여러가지를 동시에 묶어서 비동기적인 것들을 처리할 수 있다.
const fetchNumer = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(num => num * 2)
.then(num => num * 3)
.then(num => { // 새로운 promise 클래스를 넣어도 됨
return new Promise((resolve, reject) => {
setTimeOut(() => resolve(num - 1), 1000);
});
})
.then(num => console.log(num));
// 2초 뒤 5 출력
const getHen = () => {
new Promise((resolve, reject) => {
setTimeout(() => resolve('egg'), 1000);
});
}
getHen()
.then(hen => getEgg(hen)) // 받아오는 값이 하나인 경우
.then(cook) // 이 코드와 같이 생략 가능 --> 함수만 적어도 가능
.then(console.log) // egg
.catch(console.log) // error문도 하나만 받아오면 생략 가능
const getHen = () => {
new Promise((resolve, reject) => {
setTimeout(() => resolve('egg'), 1000);
});
}
getHen()
.then(hen => getEgg(hen)) // 만약 에그에서 에러가 생기면 밑에가 전부 실행 안된다.
// ⭐️ .catch('bread') ⭐️ // 이 코드를 넣어 에그의 에러가 생기면 빵을 집어 넣는다.
.then(cook)
.then(console.log) // bread 로 바뀌어서 작동
.catch(console.log)
프로미스 체이닝을 계속 실행하면 코드가 난잡해진다. 이를 위해 더 간편한 API로 async / await 을 사용하면 동기적으로 코드를 작성하는 것처럼 코드를 쉽게 작성할 수 있다.

💡 synctactic sugar
기존에 존재하는 것 위에 더 간편하게 쓸 수 있는 API를 제공하는 것
- 클래스
- async / await
✔️ 프로미스 사용
"이 작업은 시간이 너무 오래걸리니까 then을 적고 뒤에 실행할 작업을 적어두면, 지금 오래 걸리는 작업을 끝낸 후 그 코드를 실행할 것을 약속할게"
function fetchUser() {
return new Promise((resolve, reject) => {
resolve('ellie');
});
}
const user = fetchUser();
user.then(console.log);
console.log(user);
✔️ async
async 라는 키워드를 함수 앞에 붙이면 코드 블록이 자동으로 프로미스로 바뀜 ➡️ 프로미스를 사용 안해도 됨
async function fetchUser() {
return 'ellie';
}
const user = fetchUser();
user.then(console.log);
console.log(user);
✔️ await
async 키워드가 붙은 함수에서만 사용할 수 있다. 동기적으로 실행되는 코드와 비슷한 형식으로 작성할 수 있다.
async function getApple() {
await delay(3000);
return '🍎';
}
async function getBanana() {
await delay(3000);
return '🍌';
}
async function pickFruits() { // 일반 동기처리와 비슷하게 코드 작성 가능 --> 깔끔
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
}
pickFruits().then(console.log);
그러면 만약에 await을 사용하지 않았다면?
코드의 가독성이 떨어지고 콜백 지옥이 발생할 가능성이 생긴다.
✔️ await 사용 x
async function pickFruits() {
return getApple()
.then(apple => {
return getBanana()
.then(banana=> `${apple} + ${banana}`)
})
}
모든 프로미스들이 병렬적으로 실행되도록 한다.
모든 프로미스가 성공적으로 실행되면 then 작업을 실행한다.
function pickAllFruits() {
return Promise.all([getApple(), getBanana()]).then(fruits =>
fruits.join(' + ')
);
}
pickAllFruits().then(console.log);
어떤 것이든 상관없고 먼저 받아오는 하나의 프로미스를 반환한다.
function pickOnlyOne() {
return Promise.race([getApple(), getBanana()])
}
pickOnlyOne().then(console.log);