개발일기
콜백함수, Promise, async/await을 정리해보자 본문
자바스크립트에서 동기/비동기와 함께 세트로 묶어다니는 3가지
1. 콜백함수
2. Promise
3. async/await
에 대해 정리해보자
콜백함수
콜백함수는 지정한 함수를 나중에 수행하도록 하는 함수이다.
즉, 내가 원하는 때에 실행되는 함수인데, 가장 많이 드는 예로는 setTimeout()이 있다.
이 setTimeout()은 웹브라우저 api로 지정한 시간이 지나면 전달받은 함수를 수행한다.
그러니까 얘는 이렇게 생겼다.
setTimeout(함수, 시간)
예를 들어서
setTimeout(()=>console.log('hi'), 2000)
이 경우 2초뒤에 콘솔에 hi 가 출력된다.
이거시 콜백함수다.
참고로 콜백함수라고 해서 모두 비동기로 수행되는 것은 아니며 동기적으로 처리될 수도 있다!
잠깐, 동기/비동기란?
동기는 요청을 보내고 응답이 돌아와야만 다음 동작을 수행하는 것이고, 비동기는 응답을 받지 않아도 다음 동작을 수행할 수 있다.
동기는 요청에 대한 응답이 돌아올 때까지 다음 작업이 대기하고 있고, 비동기는 응답을 보내고 바로 다음 작업이 수행된다.
위에서 setTimeout()은 비동기방식으로 콘솔에 hi가 출력되기 전에 다음 동작이 수행될 수 있다.
돌아와서
비동기 콜백함수를 계속적으로 사용하게 되면 콜백지옥이라는 아주 가독성떨어지고 유지보수하기에도 어려운 코드를 작성할 수 있다.
비동기 콜백함수를 사용하면서 그 함수안에서 콜백함수를 또 부르고, 인자를 받아서 또 콜백함수를 호출하고, 에러나면 이렇게 처리해라, 근데 성공하면 또 이렇게 처리해라 어쩌구저쩌구,,,
이것을 콜백지옥이라 부르며 비동기처리에서 발생한 에러의 처리가 번거롭고,
여러개의 비동기 처리를 한번에 수행하는데에 한계가 있으므로 지양해야하는데,,,
그래서
사용하는 것이
Promise
Promise는 비동기를 간편하게 도와주는 자바스크립트 내장 오브젝트이다. 그래서
1. new를 이용해서 새로운 오브젝트를 생성할 수 있고
2. 비동기적인 것을 수행할 때 콜백함수 대신해서 사용한다
3. 그리고 장기간의 기능을 수행한 후, 성공하면 메시지+결과값을 주고, 실패하면 에러메세지를 전달한다
Promise의 포인트는 두가지이다.
1. 상태 state : 비동기 처리가 성공했는지 실패했는지에 대한 상태를 말한다.
pendding : 비동기 처리가 진행 중일 때
fulfilled : 처리 성공(성공했으면 resolve라는 함수가 실행되어 fulfilled 한 상태가 된다)
rejected : 처리 실패(실패했으면 reject라는 함수가 실행되어 rejected한 상태가 된다)
2. producer, consumer
* producer : promise를 생성
- 클래스이므로 new로 오브젝트를 생성할 수 있다.
- promise에는 resolve, reject 두 가지 콜백함수를 사용할 수 있는데 이를 executor, 실행함수라 부른다.
* consumer : promise 사용
- then, catch, finally을 이용해서 값을 받아올 수 있고, 다음 수행을 실행시킨다.
프로듀서와 컨슈머는 코드로 설명하는 것이 좋겠다
// ✅ 1. Producer (Promise 만들기)
const promise = new Promise((resolve, reject) => {
//여기에 비동기적 수행을 작성한다(시간이 걸리는 작업 = 네트워크 통신, 파일 읽어오기 등)
setTimeout(() => {
resolve("성공"); // 성공했다면 resolve 콜백함수를 통해 "성공"이라는 값을 전달해라
reject(new Error("no network")); // 실패했다면 new Error에 이유 명시하면 이것이 전달된다.
// Error : 자바스크립트에서 제공하는 오브젝트
}, 2000);
});
// ✅ 2. consumers : then, catch, finally(Promise 사용하기)
promise
.then((value) => {
//✨then : promise가 수행되고 성공했을 때 resolve의 값인 "성공"이 value에 들어온다
console.log(value);
})
.catch((error) => {
//✨catch :에러 발생 시 reject의 값이 error에 들어간다
console.log(error);
})
.finally(() => {
//성공/실패와 상관없이 무조건 수행(인자없음❌)
console.log("finally");
});
참고로, producer의 setTimeout의 첫번째 매개변수에 저렇게 resolve와 reject가 둘다 작성될 수 없다.
resolve와 reject 둘 다 작성하려면 if/else를 사용해야 한다.
setTimout(() => {
if(조건) {
//성공한다면
resolve("성공");
} else {
//실패한다면
reject("실패");
}
}
✨ promise가 생성되는 순간 해당 작업(함수)이 자동으로 실행된다.
만약 그 함수에 네트워크 요청이 들어간다면, 그리고 그 요청은 사용자가 요구했을 때만 이라면 이 방식은 사용자가 요구하지 않았는데도 바로 실행된다. -> 즉 불필요한 네트워크 통신이 일어난다.
✨ 이렇게 받아온 값 하나를 바로 전달할 경우 아래와 같이 생략이 가능하다
// promise
// .then((value) => {console.log(value);})
// .catch((error) => {console.log(error);})
promise
.then(console.log)
.catch(console.log)
✨ Promise chaining (promise끼리 연결하기)
then에는 또 다른 비동기인 promise를 전달할 수도 있다
.then((num) => {
//num이라는 값을 받아서 서버에 연결하도록
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num - 1), 1000);
});
})
✨ 아래와 같이 then을 계속 연결한 것을 then chaining 이라고도 한다.
taskA(5, 1)
.then((a_res) => {
console.log("a결과 : ", a_res);
return taskB(a_res);
})
.then((b_res) => { //return이 taskB이므로 사실 상 taskB.then()과 마찬가지
console.log("b결과 : ", b_res);
return taskC(b_res);
})
.then((c_res) => {
console.log("c결과 : ", c_res);
})
✨ 에러처리
위에 작성한 것처럼 reject(new Error())로 에러 시에는 ~을 출력해라 라고 할 수 있으나
또 다른 방법으로 에러가 났을때 A대신 B로 처리해라 이렇게도 가능하다
getHen()
.then(getEgg)
.catch((error) => {
// 에러처리 : 에러가 날수있는 부분에 에러 핸들링을 해줘서 작업에 문제가 생기지 않게 하는 것
// 아래처럼 리턴에 대신 들어갈 값을 넣어주면, 알을 받아올때 문제 발생 시 빵으로 대체하여 전달
return `빵`;
})
.then(cook)
.then(console.log)
async/await
(콜백함수를 간편하게 사용하기 위한)Promise를 더 간결하게 작성하기 위해 사용한다.
또한 async/await를 사용하면 동기적으로 실행되는 것처럼 보인다.
코드를 보자
async function fetchUser() {
await delay(1000);
return "잠온다";
}
1. async : async를 함수 앞에 쓰면 코드블록이 자동으로 promise 객체를 반환한다
2. await : async 함수 안에서만 동작한다.
await 다음의 비동기 작업이 완료될 때까지 함수 실행이 중단되고(기다리고) 작업이 완료되면 실행이 재개된다.
-> 그래서 일반적인 동기 코드처리와 동일한 흐름으로 코드를 작성할 수 있으며 코드를 읽기에도 수월해진다.!
3. return 다음에 오는 것은 성공 시 수행되는 작업이다.
Promise의 resolve 값으로 전달되는 것과 동일하다.
4. try/catch 예외처리
async function pickFruits() {
try {
const apple = await getApple();
const banana = await getBanana();
} catch() {
console.log('error')
}
'JavaScript' 카테고리의 다른 글
[딥다이브] 26. ES6 함수의 추가 기능 (0) | 2024.05.26 |
---|---|
Ajax와 Axios와 fetch 정리 (0) | 2023.06.16 |
[새싹 프론트엔드] 고차 함수 정리(map, filter, reduce, forEach) (0) | 2023.01.01 |
[새싹 프론트엔드] GRS80TM좌표계 -> WGS84좌표계 변환하기 (0) | 2022.11.26 |
[새싹 프론트앤드] JSON 데이터 통신 (0) | 2022.11.15 |