Nodejs의 비동기처리?
Nodejs는 Non-Blocking 방식으로 서버에 요청을 보냇을 때 응답이 올때까지 기다려주지 않습니다.
요청을 보내고 바로 다른일을 하다가 응답이 오면 해당 값을 사용할 수 있게 되는것이죠.
아래 비동기의 예시를 들어보겠습니다.
예시
console.log("1");
setTimeout(() => {
console.log("timeout");
} , 100);
console.log("2");
위 코드처럼 setTimeout을 넣어서 예제코드를 작성해 보았습니다.
우리가 알고있는 방식대로면
1
timout
2
이렇게 출력이 되겠지만
1
2
timeout
이렇게 출력이 됩니다.
비동기처리의 대표적인 문제사례
이 비동기 처리의 문제점에대해 대표적 예시로는 Jquery의 ajax통신이 있습니다.
const getData = () => {
let testResult;
$.get('http://example.com/', (res) => {
testResult = res;
})
return testResult;
}
console.log(getData());
http://example.com/ 에 요청을 보내면 "Javascript Callback" 이라는 response 를 준다고 가정을 해 봅시다.
해당 코드는 Javascript Callback이라는 문자를 log를 찍어내지 않고 undefined를 찍어내게됩니다.
왜냐하면, 먼저 url에 요청을 보낸 후 응답을 기다리지 않고 바로 log 를 찍어내기 때문입니다.
이럴땐 따로 비동기적 처리를 해주어야 합니다.
어떻게 해야하는지는 이제부터 알아보도록 하죠.
CallBack을 이용한 비동기 처리
가장 먼저 나왔던 해결법이 바로 CallBack을 이용하는것 입니다.
const getStrnig = (callback) => {
callback("callbackTest");
}
getString = (str => {
console.log("callbackTest");
})
Callback은 먼저 이런형식 입니다.
이 코드를 그래서 어떻게 쓰라는건데?
위의 문제의 예제를 적용해보겠습니다.
const getData = (callback) => {
$.get('http://example.com/', (res) => {
callback(res);
})
}
console.log(getData());
이런식으로 작성을 해주시면 "Javascript Callback" 이라는 문자열이 콘솔에 아주 잘 찍히게 됩니다.
콜백지옥
하지만, Callback이 정말 만능은 아닙니다.
Callback은 자칫하면 콜백지옥 이라는것에 빠질 수 있는데요
예시로 setTimeout을 이용하여 커피를 만드는 순서를 나타내 보겠습니다.
let stack = '';
setTimeout((order)=>{
console.log(stack += order);
setTimeout((order)=>{
console.log(stack += " " + order);
setTimeout((order)=>{
console.log(stack += " " + order);
}, 300, '얼음');
}, 300, '물');
},300,'에스프레소');
에스프레소
에스프레소 물
에스프레소 물 얼음
이런식으로 출력이 됩니다.
그런데 이렇게 하게되면 setTimeout이 너무 중첩되어 보기가 힘들고 가독성이 떨어집니다.
이런형태를 보고 바로 콜백지옥 이라고 합니다.
이 콜백지옥을 해결하는 방법은 3가지로 나눌 수 있습니다.
기명함수, Promise, async
기명함수
위 콜백지옥에서 나온 코드를 기명함수로 아래와같이 나타낼 수 있습니다.
let stack = '';
const firstStep = (order) => {
console.log(stack += order);
setTimeout(secondStep , 300 , '물')
}
const secondStep = (order) => {
console.log(stack += " " + order);
setTimeout(thirdStep , 300 , '얼음')
}
const thirdStep = (order) =>{
console.log(stack += " " + order);
}
setTimeout(firstStep, 300 , "에스프레소")
이런식으로 나타낼 수 있습니다.
가독성은 좋지만, 단점으로는 일회성 함수를 계속해서 변수로 명시를 해주어 사용하는것이 굉장히 비효율적 입니다.
이 부분을 대체하기 위하여 Promise와 async가 있습니다.
Promise
new Promise( (resolve) => {
setTimeout(()=>{
let stack = '에스프레소'
console.log(stack)
resolve(stack);
},300);
}).then((prevStack) =>{
return new Promise((resolve) => {
setTimeout(()=>{
console.log(prevStack += " " + "물");
resolve(prevStack);
},300);
});
}).then((prevStack)=>{
return new Promise((resolve) => {
setTimeout(()=>{
console.log(prevStack += " " + "얼음");
resolve(prevStack);
},300);
});
})
Promise를 사용한 코드로 위에서 아래로 진행을 하는 코드이며
이런형태로 작성을 하게 된다면 동기처럼 보이게 하는 코드가 완성이 됩니다.
하지만 더 간단하게 작성하는 방법이 있습니다.
const addStack = (order) =>{
return (prevStack) => {
return new Promise((resolve) => {
setTimeout(()=>{
const stack = prevStack? `${prevStack} ${order}` : order;
console.log(stack);
resolve(stack);
},300);
});
};
};
addStack('에스프레소')()
.then(addStack('물'))
.then(addStack('얼음'));
이런식으로 더 짧게 작성을 할 수 있습니다.
잘 보시면 반복되는 부분이 보이는데 해당 부분을 함수화하여 고차함수로 간단하게 만드는것 입니다.
addStack이 끝나지 않아 계속해서 prevStack에는 전에 저장되었던 문자가 저장이 되어있어 중첩이 가능한 것 입니다.
글이 너무 길어져 async await과 Promise에대한 자세한 글과 다음에 작성하겠습니다.
'JavaScript > Nodejs' 카테고리의 다른 글
[NodeJS] 로그인/회원가입 구현하기 (로그인편) (4) | 2021.05.20 |
---|---|
[NodeJS] 로그인/회원가입 구현하기 ( 회원가입편 ) (3) | 2021.05.20 |
[Node.js] 콜백지옥 벗어나기 async / await (1) | 2021.02.06 |
[Node.js] 메이플스토리 api 사용하기(2) - 크롤링, SoapApi (2) | 2020.12.16 |
[Node.js] 메이플스토리 api 사용하기(1) - 크롤링, SoapApi (0) | 2020.12.16 |