콜백 함수를 이용한 동기/비동기적 처리
동기적 처리란 일반적으로 위에서 아래로 실행되는 코드를 처리하는 것을 말한다.
하나의 작업을 끝내야 다음 작업을 실행할 수 있는 방식이다.
직관적이지만 작업이 오랜 시간이 걸리는 작업이 끝나지 않으면 뒤에서 실행할 작업이 아무리 간단한 작업이라도 소요시간이 오래 걸릴 수밖에 없다.
비동기적 처리란, 작업을 지시하고 작업이 진행되는 동안 다른 작업을 시작할 수 있다.
따라서 동기적 처리보다 복잡하지만 효율적이다.
- setTimeout 메소드를 통해 작성한 비동기적 처리를 보자.
console.log("Nice to meet you");
setTimeout(() => {
console.log("Timer is done");
fetchData((text) => {
console.log(text);
});
}, 2000);
console.log("Hello");
console.log("Hi");
→ Nice to meet you
Hello
Hi
// 약 2초 뒤
Timer is done
- 위 코드를 실행해 보면 위에서 동기적 코드로 작성된 "Nice to meet you" , "Hello", "Hi" 가 먼저 출력되고, 약 2초(2000ms) 뒤 "Timer is done" 이 출력되는 것을 볼 수 있다.
- 비동기적으로 setTimerout 메소드로 실행한 코드에게 작업을 지시하고 그 작업을 수행하는 동안 아래에 있는 "Hello", "Hi"코드를 실행한 것이다.
- 비동기적 코드를 하나 더 추가한 예시를 보자.
const fetchData = (callback) => {
setTimeout(() => {
callback("Done!");
}, 1500);
};
console.log("Nice to meet you");
setTimeout(() => {
console.log("Timer is done");
fetchData((text) => {
console.log(text);
});
}, 2000);
console.log("Hello");
console.log("Hi");
→ Nice to meet you
Hello
Hi
// 약 2초 뒤
Timer is done
// 약 1.5초 뒤
Done
- fetchData 라는 함수의 매개변수로 약 1.5초 뒤에 "Done" 을 출력하는 setTimeout 함수를 넣었다.
- 이 콜백함수는 호출이 되지 않았기 때문에 아직 "Done" 을 출력하지 않는다.
- 두번째 setTimeout 함수 단락에서 "Timer is done" 을 출력하고 fetchData 함수를 호출하는데, 이 때 매개변수로 입력한 text 를 출력한다.
- text는 첫 번 째 함수 단락의 매개변수에는 callback의 매개변수인 callback("Done!") 이 들어있기 때문에 1.5초(1500ms) 후에 Done을 출력한다.
-하지만 이런 방식은 콜백함수를 계속해서 여러 번 중첩해서 사용하면 코드가 점점 깊어지고 난해한 콜백지옥에 갇히게 된다.
- 이러한 문제점을 바탕으로 Promise 라는 개념이 등장하게 되었다.
Promise
Promise 는 콜백함수를 보다 직관적으로 나타내기 위해 등장한 객체이다.
- Promise 객체의 기본 형태
const 변수 = new Promise(executor)
- Promise 가 만들어 질 때 executor 를 인자로 가지며, executor 에는 함수만 올 수 있다.
- executor의 인자로는 resolve, reject가 주입된다.
- executor는 Promise의 실행함수로, Promise가 만들어질 때 자동으로 생성된다.
Promise는 3가지 상태가 진행되며 실행이 된다.
- 대기(Pending) : 이행되거나 거부되지 않은 초기 상태
- 이행(Fulfilled) : 연산이 성공적으로 완료된 상태
- 거부(Rejected) : 연산이 실패한 상태
Promise 를 사용하기 위해 먼저 new 생성자를 이용해 Promise 를 생성한다.
const fetchData = () => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Done!");
}, 1500);
});
return promise;
};
- 두 번째 줄에서 promise 상수에 Promise 를 생성자로 가져와 매개변수로는 resolve 와 reject 함수를 콜백하게 되는데 resolve 는 Promise 객체의 연산이 성공적으로 완료(Fulfilled)되었을 때 실행하는 함수이고, reject는 연산에 실패(Reject)되었을 때 실행하는 함수이다.
- 이 fetchData 함수는 Promise 1.5 초 뒤에 "Done" 을 출력하는 setTimeout 메소드를 리턴하게 된다.
const fetchData = () => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Done!");
}, 1500);
});
return promise;
};
console.log("Nice to meet you");
setTimeout(() => {
console.log("Timer is done");
fetchData()
.then((text) => {
console.log(text);
return fetchData();
})
.then((text2) => {
console.log(text2);
});
}, 2000);
console.log("Hello");
console.log("Hi");
→ Nice to meet you
Hello
Hi
// 2초 뒤
Timer is done
// 1.5초 뒤 text
Done!
// 1.5ch 뒤 text2
Done!
- Promise 가 만들어질 때 executor 가 실행되는데, executor 의 resolve("Done!") 함수는 두 번 째 함수 단락에서
fetchData().then (...) 가 실행 되어야지 fulfilled 상태가 되며 실행되게 된다.
- 독립적인 블록에서 then 을 사용해 비동기적으로 콜백함수를 호출하고 있어 콜백함수만을 사용한 것보다 직관적이고 간결한 것을 볼 수 있다.
- 하지만 여전히 중첩이 여러번 될 경우 코드가 복잡해 질 수 있기 때문에 ES7 부터는 async, await 구문이 등장하게 되는데 이는 따로 작성하겠다.
'JavaScript' 카테고리의 다른 글
객체지향(Object-Oriented) (0) | 2022.12.10 |
---|---|
JavaScript, 비동기함수 와 await(async/await) (0) | 2022.11.25 |
JavaScript, 예외처리 (0) | 2022.11.23 |
JavaScript, Array 함수(forEach, map, filter, some, every, find, findindex) (0) | 2022.11.23 |
JavaScript, 호이스팅과 TDZ (0) | 2022.11.18 |