2장 (1/3): CPS 패턴
이 글은 CPS 패턴과 CPS가 Node.js에서 어떻게 사용되고, 어떤 점을 주의해야 하는지 다룬다.
1. CPS 패턴
Node.js는 1장에서 살펴봤듯 비동기 특성을 가지며, 따라서 Node.js 앱은 대부분의 일을 비동기로 처리할 수 밖에 없다. 비동기를 처리하는 방법 중 CPS, Continous Passing Style을 소개한다.
CPS: 비동기 API를 사용할 때, 콜백 함수를 인자로 넘기는 패턴이다.
- 왜 사용하는가: 비동기 API는 return을 할 수 없는데, 함수의 실행이 끝나기 전에 제어권이 넘어가기 때문이다. 이를 해결하기 위해선 결과를 다른 함수에 넘기면 된다.
- 장점: 간단하고 효과적이다.
- 단점: 호출 깊이가 깊어지면 가독성이 감소된다. Callback Hell이라고 불린다.
2. Node.js에서의 CPS 패턴
Node.js는 CPS 패턴을 사용할 때 일관된 규칙을 따라야 한다.
- argument 순서에 관한 규칙:
(...params, callback)
과 같이, callback 함수를 마지막 인자로 넘겨야 한다. - callback 함수의 argument에 관한 규칙:
(err, ...args)
와 같이, err가 첫 인자여야 한다. err
인자의 경우, 항상Error()
객체여야 한다. (이 부분은 잘 지켜지지 않는 듯 하다.)
3. CPS 패턴의 콜 스택
Node.js에서 비동기 API를 호출하는 경우, callback 함수는 프로그래머가 예상한 호출 순서로 구성된 스택을 갖지 않는다. 비동기 API가 완료됐을 때, 이벤트 루프에 의해 단일 함수로 Queue에 쌓인 후 다른 타이밍에 실행되기 때문에 새로운 스택에서 실행된다. 비동기 함수에서 예외를 던지면, Error
를 반환하며 프로세스가 종료된다.
1 | const fs = require('fs'); |
4. Node.js에서 비동기를 처리할 때 절대 하지 말아야 할 점들
1. 결괏값을 동기, 비동기 2가지 방식으로 전달하지 않는다.
결괏값이 비동기일것을 기대하고 이벤트 리스너를 등록할 때, 동기로 결괏값이 제공되는 경우 이벤트 리스너가 동작하지 않는다.
동기 반환값을 비동기화 한다.
setTimeout, setImmediate, nextTick, Promise
등이 가능하다.
2. Callback 함수를 argument로 받는 동기 함수를 작성하지 않는다.
- 동기 API는 바로 결괏값을 받는 형태로 코드를 작성하면 된다.