1. 동기 - synchronous
코드는 위에서 아래로 순차적으로 실행된다. 예를 들어 집안일이라고 가정을 하겠다.
1번 : 빨래를 돌린다. // 1시간
2번 : 설겆이 // 걸리는 시간 10분
3번 : 청소를 한다. // 30분
이라고 했을때 빨래를 먼저 실행하고 그다음에 설겆이를 한다. 설겆이를 마치고 나서 그다음에 청소를 하게되고 마무리가 되면 오늘의 집안일은 끝나며 총 걸린 시간은 위 세가지 작업을 합친 1시간 40분이 되겠다.
2. 비동기 - asynchronous
1번 : 빨래를 돌린다. // 1시간
2번 : 설겆이 // 걸리는 시간 10분
3번 : 청소를 한다. // 30분
빨래를 세탁기에 먼저 돌려놓고 세탁기가 돌아가는 동안 설겆이를 하고 마치면 청소를 한다. 그리고 세탁기가 다 돌아가 빨래가 끝나면 오늘의 집안일은 끝나며 빨래가 돌아가는 동안 다른 집안일을 모두 수행할수 있어 위 세가지 작업을 마치는 시간은 1시간+@ 정도이다. 동기식 보다는 좀더 빠르게 작업을 효율적으로 할수있다.
일단 먼저 개념먼저 짚고 넘어가겠다.
... main.js page
function outer() {
function inner() {
return console.log("inner 함수 호출")
}
inner()
return console.log("outer 함수 호출")
}
outer()
console.log("main 페이지 실행")
이렇게 메인페이지를 실행하게되면 메인페이지 => outer 함수 호출 => inner 함수 호출 의 형태로 실행이 되는데 결과물의 반환 순서는
inner 함수 호출
outer 함수 호출
main 페이지 실행 이라는 콘솔 결과가 나오게 된다.
위의 스택과는 반대로 먼저 작업대에 올라간 작업물 순서대로 결과물이 나오게 된다.
예)
1. 음식점 카운터 에서 주문을 받는다.
2. 그 주문을 주방에 전달을 한다.
3. 주방은 요리를 만들고 있고 카운터는 계속해서 주문을 받고있다.
주방이 백그라운드인 셈이다.
- 작업물들을 스택에 주문을 받아놓는다.
- 스택에서 작업시간이 긴 작업을 백그라운드에 넘김
- 백그라운드에서 완성된 결과물이 콜백큐 에서 대기중
- 이벤트루프가 스택에 작업물이 있는지 확인
- 없으면 콜백큐에 있는 결과물을 스택에 올려놓고 작업완료
- 콜백큐에 작업물이 없고 스택에도 작업이 없으면 main 종료
Node.js가 비동기처리를 하는 함수나 메소드중 내가 알고있는것은
- setTimeout
- setInterval
- Ajax
- Request
- fetch
- axios
- 데이터베이스 쿼리문
물론 더 있겠지만 내가 알고있는건 이상태 이고 예)시퀄라이즈 공식문서
공식문서를 보면 어떤 함수나 쿼리, 메소드가 비동기방식으로 작업을 처리하는지 알수있다.
그러면 무조건 비동기가 좋은게 아니냐 라고 한다면 아직 주니어 개발자의 입장에서 확답을 내릴수는 없다. 하지만 작업이라는게 일을 동기식으로 진행을 해야할 때가 있고 비동기식으로 해야할 때가 나뉘어지는데 그건 직접 경험해보고 적절히 적용해주는게 좋을것 같다.
이번에도 예를 들어보겠다.
1번 : 빨래를 세탁기에 돌린다.
2번 : 완성된 빨래를 건조기에 돌린다.
3번 : 건조가 완성된 옷들을 개서 옷장에 넣어둔다.
위와같은 집안일이 있을때 내가 사용하는 Node.js 같은경우엔 작업이 큰 빨래같은경우 내 의지와 상관없이 스택에 올려놓은 다음에 백그라운드로 빼서 작업을 진행시킨다.
위와같은 문제로 인해 나온 비동기처리 방식이 있다.
- 콜백함수
- promise (resolve, reject)
- then & catch
- async & await
콜백함수란 나중에 실행되는 함수로 비동기 작업이 끝나고 난뒤 실행되는 함수이다.
setTimeout((arg)=>{
console.log(arg)
setTimeout((arg)=>{
console.log(arg)
setTimeout((arg)=>{
console.log(arg)
setTimeout((arg)=>{
console.log(arg)
}, 1000, "네번째 콜백")
}, 1000, "세번째 콜백")
}, 1000, "두번째 콜백")
}, 1000, "첫번째 콜백")
이러한 콜백지옥의 문제로 가독성도 떨어져 ES6에 promise 객체가 나왔다.
프로미스 객체는 콜백함수의 콜백지옥을 해결하기 위해 나왔다.
const test = new Promise((resolve, reject)=>{
if(resolve){
resolve("성공")
}
if(reject){
reject("실패")
}
});
console.log(test) // Promise { <pending> }
하지만 프로미스를 써서 비동기처리를 하게되면 반환값이 프로미스 객체로 반환되게 되는데 이때 사용되는것이 then과 catch이다.
const test = new Promise((resolve, reject)=>{
if(resolve){
resolve("성공")
}
if(reject){
reject("실패")
}
});
test.then(result=>{
return console.log(result)
})
.catch(err=>{
return console.log(result)
})
// "성공"
프로미스를 사용해서 성공시에는 then에 인자로 닮겨서 사용이 가능하고 실패시 catch에 담겨서 예외처리를 할수있다.
프로미스객체의 상태 3가지
Pending(대기) : 미완료 상태
Fulfilled(이행) : 완료 상태
Rejected(실패) : 실패 상태
ES2017에 나온 문법이며 프로미스 객체를 좀더 사용하기 쉽게 만들어진게 async & await이다.
const test = async () => {
const test = await 비동기함수
}
이런식으로 함수앞에 async를 달아주고 await으로 비동기 코드를 호출하여 바로 사용할수 있게끔 해준다.
비동기 처리 방식은 적절히 상황에 맞게 사용하면 될것같다.
참고 블로그: