동기 : I/O 작업이 진행되는 동안 작업이 중단된 채 대기하는 방식으로 요청을 하고 완료할 때까지 무한정 기다려야 한다.
비동기 : 요청을 하고 바로 제어권을 돌려받는 방식으로 요청을 하고 기다리지 않고 다른 작업을 처리하다가 결과가 오면 처리하므로 자원을 효율적으로 사용할 수 있다.
비동기의 장점
1. 네트워크 응답 처리 - 서버에게 요청을 보냈을 때 응답이 언제 올지 알 수 없으므로 비동기로 실행
2. 파일 시스템 작업
3. 알람 같은 의도적인 시간 지연이 필요한 경우 - 스레드의 블록킹이 발생해 응답이 올 때까지 화면이 멈춰있을 것이다. 이런 경우를 피하기 위해 비동기로 실행
Node.js는 비동기로 실행이 되므로 노드들 사이에 순차적인 작업이 일어나야 하는 경우 흐름을 제어해야 한다.
비동기로 실행되면서 우리가 원하는 순서를 유지할 수는 없을까 ❓
첫 번째 방법은 콜백 함수를 이용하는 것이다.
콜백 함수란 어떤 이벤트가 발생하거나 특정 시점에 도달했을 때 함수를 호출하여 흐름을 제어하는 것으로 함수를 호출하기 전까지 다른 일을 한다.
👀 콜백 함수 사용법
Mutiply 함수의 매개변수로 a, b, callback(함수)을 받는 것이고 6번째 라인에서 함수를 호출한다. 이때 a = 5, b = 2가 되어 5*2=10의 값이 result 변수에 담긴다. 그리고 callback 함수에 result값을 넣어 호출하므로 result값이 response에 담긴다. 따라서 출력할 시 10이 출력된다.
🧛♀️ callback hell 발생
콜백 지옥은 비동기 처리 로직을 로직을 위해 콜백 함수를 연속해서 사용해서 발생하는 문제로 콜백 함수 내부에 콜백 함수가 있고 또 그 내부에 콜백 함수가 있는 코드가 깊어지고 가독성이 굉장히 떨어지는 문제가 발생한다.
순차적인 처리가 가능한 다른 방법은 없을까 ❓
1️⃣ Promise
프로미스는 자바스크립트 비동기 처리에서 사용되는 객체로써 ES6부터 공식적으로 포함된 흐름 제어 패턴이다.
Promise의 3가지 상태(=처리과정)
- Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태, 즉 최초 생성된 시점의 상태
- Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태, 즉 작업이 성공적으로 완료된 상태
- Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태, 즉 작업이 실패한 상태
Pending(대기)
new Promise() 메서드는 콜백 함수를 선언할 수 있고 콜백 함수의 인자로는 동작에 대한 결과를 올바르게 줄 수 있으면 resolve함수 호출, 동작에 실패했으면 reject 함수를 호출한다.
Fulfilled(이행)
콜백 함수의 인자 resolve를 위와 같이 실행하면 이행 상태이다.
Rejected(실패)
콜백 함수의 인자 reject을 위와 같이 실행하면 실패 상태이다.
성공한 결과 값과 실패한 결과 값은 어떻게 받을 수 있을까 ❓
<Promise>.then() : 비동기 작업이 완료 시, 즉 Fulfilled 상태라면 결과에 따라 함수 호출
<Promise>.then().catch() : 비동기 작업이 중간에 에러가 발생할 때, 즉 Rejected 상태일 경우 호출
💡 Promise Chaning
여러 개의 프로메스들을 연결하여 사용하는 것으로써 then() 함수를 호출하면 새로운 프로미스 객체가 반환 값이 되기에 가능한 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
const func1 = (param) =>{
return new Promise((resolve, reject) =>{
setTimeout (() => {
console.log('func1 return resolved');
resolve(`func1 resolved: ${param}\n`);
}, 500);
});
}
const func2 = (param) =>{
return new Promise((resolve, reject) =>{
setTimeout (() => {
console.log('func2 return rejected');
reject(new Error(`func2 rejected : ${param}\n`));
}, 500);
});
}
const func3 = (param) =>{
return new Promise((resolve, reject) =>{
setTimeout (() => {
console.log('func3 return resolved');
resolve(`func3 resolved: ${param}\n`);
}, 500);
});
}
const func4 = (param) =>{
return new Promise((resolve, reject) =>{
setTimeout (() => {
console.log('func4 return rejected');
reject(new Error(`func4 rejected : ${param}\n`));
}, 500);
});
}
const chain = func1('sehee');
chain.then((result) => func2(result))
.catch((result) => console.error(result))
.then((result) => func3(result))
.then((result) => func4(result))
.catch((result) => console.error(result))
|
cs |
func1의 파라미터 값으로 sehee을 받아와서 func2에 넣어준다. func2에는 reject을 호출하여 error을 발생시켰으므로 catch()을 사용하여 에러를 잡는다. func4의 경우도 마찬가지이다.
func2와 func4에서 에러가 발생한 것을 확인할 수 있고 func3의 파라미터가 undefinded인 이유는 func2의 에러가 발생한 Promise 객체를 반환받았기 때문이다.
✌ isMonHappy가 True이면 Phone JSON 반환 아니면 mom is not happy 출력하기
참고자료
'Server > Node.js' 카테고리의 다른 글
Async와 Await로 흐름 제어하기 (1) | 2021.03.16 |
---|