동기 vs 비동기에 관해서 내가 쓴 글
동기 함수의 경우 함수 호출 후 종료할 때까지 다른 작업은 수행하지 않고 기다린 다음 원래 작업을 수행한다. 그렇지만 비동기 함수 호출 후 원래 작업을 계속 수행, 즉 다른 스레드에서 함수 두 개가 동시에 수행되는 효과를 누릴 수 있다.
그렇다면 여기서 문제가 발생하는데 과연 비동기 함수 호출 후 그 함수의 리턴값을 통해 무언가 새로운 값을 도출하고 싶다면 어떻게 해야 할까??
그 답은 바로 콜백함수 이다.
// first
setTimeout(() => {
console.log("setTimeout 시작");
}, 3000);
// later
setTimeout(() => {
console.log("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!");
}, 2000);
아래의 결과는 다음과 같다.
나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!
setTimeout 시작
그렇다면 원래와 같은 값을 도출해내려면 어떻게 해야할까??
// first
setTimeout(() => {
console.log("setTimeout 시작");
// later (콜백함수)
setTimeout(() => {
console.log("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!");
}, 2000);
}, 2000);
다음과 같이 시작하려는 함수 안에 해당 함수를 넣으면 된다.
만약에 이러한 상황이 수십 수백 개가 있다면 어떻게 될까?? 그렇게 될 경우 코드 가독성은 매우 엉망이 되버리고 실제로 웹은 대부분의 작업들이 비동기로 이루어지기 때문에 이런 콜백 지옥에 빠져선 안된다.
Q. 그렇다면 이런 콜백지옥을 해결할 수 있는 방법은 무엇일까??
A. 바로 Promise 와 async-await이다.
비동기 함수를 동기 처리하기 위해 고안한 객체입니다.
작업 결과에 따라 성공(.then) 또는 실패(.catch)를 리턴하며 결과 값을 전달 받을 수 있습니다.
pending(대기) : 처리가 완료되지 않은 상태
fulfilled(이행) : 성공적으로 처리가 완료된 상태
rejected(거부) : 처리가 실패로 끝난 상태
State : pending -> fulfilled or rejected
// 클로저 구현을 통해 해당 함수 실행 시 text 변수와 Promise 객체를 동시에 사용하게 하기 위해서
function writeText(text){
return new Promise((resolve, reject) => {
setTimeout(() =>{
resolve(text);
},2000);
})
}
let ThisIsText = writeText("setTimeout 시작");
ThisIsText
.then((text) => {
console.log(text);
return writeText("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!");
})
.then((text) => console.log(text));
코드 설명:
내가 비동기로 실행하고 싶은 함수를 Promise로 처리한다. 이 때 Promise chain 방식을 이용하면 비동기 함수 호출 후의 동작을 다시 구현할 수 있게 된다.
// 출력
setTimeout 시작
나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!
무엇보다도 콜백지옥에서 벗어나게 해주었으며 각각의 비동기 함수에 대해 유지보수 + 가독성이 기존 콜백 지옥보다 너무나도 좋아졌다. 그리고 콜백함수의 경우 해당 콜백 함수에 대한 에러처리를 모두 적어주어야 하였는데 Promise의 경우 단 하나의 .catch로 같은 에러의 경우 하나의 구문으로 모든 처리가 가능하다.
하지만 promise객체의 단점은 .then지옥에 빠지기 쉽고 생각보다 가독성이 좋지 못하다.
따라서 이를 보완하여 나온 것이 바로 async-await이다.
위와 똑같은 예제를 async-await로 작성해보겠다.
// 클로저 구현을 통해 해당 함수 실행 시 text 변수와 Promise 객체를 동시에 사용하게 하기 위해서
function writeText(text){
return new Promise((resolve, reject) => {
setTimeout(() =>{
resolve(text);
},2000);
})
}
async function doit(){
try{
// console.log(foo); // 지정하지 않은 변수 출력
console.log(await writeText("setTimeout 시작"));
console.log(await writeText("나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!"));
} catch (err) {
console.log("ㅇㅔ러 발생")
}
}
doit();
// 나 setTimeout 실행 후 2초 뒤에 다음 실행할 거임!!
// setTimeout 시작
내가 비동기 처리를 하고 싶은 함수들을 async함수에 집어 넣고 그 함수 안에 각 비동기함수들을 동기 호출하기 위해 await를 사용한다.
이때 await 객체의 반환값으로는 우리가 지정해 주었던 Promise의 resolve함수의 인자값이다. 그래서 위의 코드에서 보는 것처럼 바로 console.log를 해주면 내가 위의 예제와 똑같이 실행되는 것을 볼 수 있다.
해당 비동기 처리에 오류 구문을 잡기 위해 try-catch구문 을 사용하여 잡을 수 있다.
비동기를 공부하다보니 단순 setTimeout구문 외 ajax통신 그리고 비동기로 처리(?? 사실 개념이 모호...)하는 dom객체 에 대해 좀 더 공부하면 좋겠다라는 생각을 했다. 비동기가 처음이기도 하고 내가 짠 비동기 코드 예제로 설명하다보니 뭔가 글로 적어 설명한다는 게 너무나 어려웠다. 이는 내가 개념이 부족하다는 뜻이라 생각한다. 그래서 틈틈히 더 공부해보고 글을 고쳐나갈 생각이다.
(callback)
[캡틴 판교] https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/
https://www.youtube.com/watch?v=U42qWURR6Gw
(promise)
[추천 : 굿굿] https://infoscis.github.io/2018/02/27/ecmascript-6-promises-and-asynchronous-programming/
https://sangminem.tistory.com/284
[mdn] https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
[캡틴 판교]https://joshua1988.github.io/web-development/javascript/promise-for-beginners/
(async-await)
[캡틴판교] https://joshua1988.github.io/web-development/javascript/js-async-await/
https://www.javatpoint.com/javascript-async-and-await
https://hangem-study.readthedocs.io/en/latest/javascript/async/