3장 노드 기능 🚀
3.1 REPL 사용하기
REPL : 입력한 코드를 읽고 (Read), 해석하고 (Eval), 결과물을 반환하고 (Print), 종료할 때까지 반복하는 (Loop) 노드의 콘솔
한두 줄짜기 코드를 테스트해보기엔 좋지만 여러 줄의 코드를 실행하기엔 불편하다.
3.2 JS 파일 실행하기
js파일을 만들고 콘솔에서 node [자바스크립트 파일 경로]
로 실행한다.
3.3 모듈로 만들기
노드는 브라우저 자바스크립트와 달리 코드를 모듈로 만들 수 있다.
모듈 : 특정한 기능을 하는 함수나 변수들의 집합. 보통 파일 하나가 모듈 하나가 된다.
// var.js
const odd = '홀수입니다';
const even = '짝수입니다';
module.exports = {
odd,
even,
};
// func.js
const { odd, even } = require('./var');
function checkOddOrEven(num) {
if (num % 2) {
return odd;
}
return even;
}
module.exports = checkOddOrEven;
// index.js
const { odd, even } = require('./var');
const checkNumber = require('./func');
function checkStringOddOrEven(str) {
if (str.length % 2) {
return odd;
}
return even;
}
console.log(checkNumber(10));
console.log(checkStringOddOrEven('hello'));
3.4 노드 내장 객체 알아보기
3.4.11 global
브라우저의 window와 같은 전역 객체. 모든 파일에서 접근할 수 있다.
global은 생략 가능 (global.require → require)
3.4.2 console
보통 디버깅을 위해 사용.
메서드 | 설명 |
---|---|
console.time(레이블) |
console.timeEnd (레이블) 과 대응되어 같은 레이블을 가진 time과 timeEnd 사이의 시간을 측정한다. |
console.log(내용) |
평범한 로그를 콘솔에 표시. |
console.error(에러 내용) |
에러를 콘솔에 표시. |
console.table(배열) |
배열의 요소로 객체 리터럴을 넣으면, 객체의 속성들이 테이블 형식으로 표현된다. |
console.dir(객체, 옵션) |
객체를 콘솔에 표시할 떄 사용. |
console.trace(레이블) |
에러가 어디서 발생했는지 추적할 수 있다. |
3.4.3 타이머
메서드 | 설명 |
---|---|
setTimeout(콜백 함수, 밀리초) |
주어진 밀리초 이후에 콜백 함수를 실행 |
setInterval(콜백 함수, 밀리초) |
주어진 밀리초마다 콜백 함수를 반복 실행 |
setImmediate(콜백 함수) |
콜백 함수를 즉시 실행 |
clearTimeout(아이디) |
setTimeout를 취소 |
clearInterval(아이디) |
setInterval를 취소 |
clearImmediate(아이디) |
setImmediate를 취소 |
3.4.4 filename, dirname
- __filename : 현재 파일명
- __dirname : 현재 파일 경로 제공
3.4.5 module, exports, require
module.exports === exports
두 객체는 참조 관계에 있다. (= 같은 객체를 바라보고 있음). 그러므로 한 모듈에 동시에 사용하는 것은 권장하지 않음.
require
모듈을 불러오는 객체. 순환 참조가 있을 경우 순환 참조되는 대상을 빈 객체로 만든다.
require.cache
: require된 파일들의 정보를 담고 있다. 파일 이름을 속성명으로 갖고 파일의 모듈 객체가 속성값으로 들어 있다.require.main
: 노드 실행 시 첫 모듈을 가리킨다.
3.4.6 process
현재 실행되고 있는 노드 프로세스에 대한 정보를 담고 있다. 운영체제나 실행 환경 별로 다른 동작을 하고 싶을 떄 사용.
메서드 | 설명 |
---|---|
process.version |
설치된 노드의 정보 |
process.arch |
프로세서 아키텍처 정보 |
process.platform |
운영체제 플랫폼 정보 |
process.pid |
현재 프로세스의 아이디. |
process.uptime() |
프로세스가 시작된 후 흐른 시간. 단위는 초. |
process.execPath |
노드의 경로 |
process.cwd() |
현재 프로세스가 실행되는 위치 |
process.cpuUsage() |
현재 cpu 사용량 |
3.4.6.1 process.env
시스템의 환경 변수 정보를 담고 있다.
서버나 데이터베이스의 비밀번호, 각종 API 키 등을 저장하는 공간으로도 사용
3.4.6.2 process.nextTick(콜백)
이벤트 루프가 다른 콜백 함수들보다 nextTick
의 콜백 함수를 우선으로 처리하도록 만든다.
3.4.6.3 process.exit(코드)
실행 중인 노드 프로세스를 종료.
인수를 주지 않거나 0
을 주면 정상 종료, 1
을 주면 비정상 종료를 의미함.
3.5 노드 내장 모듈 사용하기
3.5.1 os
메서드 | 설명 |
---|---|
os.arch() |
process.arch 와 동일 |
os.platform() |
process.platform 과 동일 |
os.type() |
운영체제의 종류를 보여준다 |
os.uptime() |
운영체제 부팅 이후 흐른 시간(초)를 보여준다. |
os.hostname() |
컴퓨터의 이름 |
os.release() |
운영체제의 버전 |
os.homedir() |
홈 디렉터리 경로 |
os.tmpdir() |
임시 파일 저장 경로 |
os.cpus() |
컴퓨터의 코어 정보. os.cpus().length = 코어 개수 확인 |
os.freemem() |
사용 가능한 메모리(RAM) |
os.totalmem() |
전체 메모리 용량 |
3.5.2 path
폴더와 파일의 경로를 쉽게 조작하도록 도와주는 모듈. 운영체제별로 경로 구분자가 다르기 때문에 사용.
메서드 | 설명 |
---|---|
path.sep |
경로의 구분자. 윈도는 \, POSIX(MAC, LINUX)는 / |
path.delimiter |
환경 변수의 구분자. 윈도는 세미콜론(;), POSIX는 콜론(:) |
path.dirname(경로) |
파일이 위치한 폴더 경로 |
path.extname(경로) |
파일의 확장자 |
path.basename(경로, 확장자) |
파일의 이름(확장자 포함)을 표시. 이름만 표시하고 싶다면 두 번째 인수로 파일의 확장자를 추가 |
path.parse(경로) |
파일 경로를 root, dir, base, ext, name으로 분리 |
path.format(객체) |
path.parse()한 객체를 파일 경로로 합친다. |
path.normalize(경로) |
/나 \를 실수로 여러 번 사용했거나 혼용했을 때 정상적인 경로로 변환 |
path.isAbsolute(경로) |
파일의 경로가 절대경로인지 상대경로인지 true, false로 알림. |
path.relative(기준경로, 비교경로) |
경로를 두 개 넣으면 첫 번째 경로에서 두 번째 경로로 가는 방법을 알린다. |
path.join(경로, ...) |
여러 인수를 넣으면 하나의 경로로 합친다. |
path.resolve(경로, ...) |
join이 상대 경로로 처리한다면 resolve는 절대 경로로 인식해서 앞의 경로를 무시한다. path.join('/a', '/b', 'c'); // /a/b/c/ , path.resolve('/a', '/b', 'c'); // /b/c |
3.5.3 url
인터넷 주소를 쉽게 조작하도록 도와주는 모듈
처리 방법
1. WHATWG 방식
버전 7에서 추가. new URL(주소) 를 사용하여 객체를 생성하고 url.format(객체)으로 합칠 수 있다.
기존 방식에는 없는 username, password, origin,searchParams 속성이 있다.
searchParams
: 주소를 통해 데이터를 전달할 때 사용. 물음표(?)로 시작하고 키=값 형식으로 데이터를 전달. 여러 키가 있을 경우 &로 구분
searchParams 메서드
메서드 | 설명 |
---|---|
getAll(키) |
키에 해당하는 모든 값을 가져온다. |
get(키) |
키에 해당하는 첫 번째 값 |
has(키) |
해당 키가 있는지 검사 |
keys() |
모든 키를 객체로 반환 |
values() |
모든 값을 객체로 반환 |
append(키, 값) |
해당 키를 추가. 같은 키가 있다면 유지하고 하나 더 추가 |
set(키, 값) |
append 와 유사하지만 같은 키의 값을 모두 지우고 새로 추가 |
delete(키) |
해당 키를 제거 |
toString() |
조작한 searchParams 객체를 다시 문자열로 만든다. |
2. 기존 방식 url
url.parse(주소)
를 사용하여 주소를 분해하고url.format(객체)
으로 합칠 수 있다.- host부분 없이 pathname 부분만 오는 주소인 경우 WHATWG방식이 처리할 수 없으므로 기존 방식을 사용한다.
3.5.4 querystring
기존 노드의 url을 사용할 때, search 부분을 사용하기 쉽게 객체로 만드는 모듈
querystring.parse(쿼리)
: 쿼리 부분을 자바스크립트 객체로 분해querystring.stringify(객체)
: 분해된 query 객체를 문자열로 다시 조립
3.5.5 crypto
다양한 방식의 암호화를 도와주는 모듈
3.5.5.1 단방향 암호화
복호화할 수 없는 암호화 방식. = 해시 함수
crypto.createHash('sha512').update('비밀번호').digest('base64');
형태로 사용.
createHash(알고리즘)
: 사용할 해시 알고리즘을 넣는다. md5, sha1, sha256, sha512 등update(문자열)
: 변환할 문자열 추가digest(인코딩)
: 인코딩할 알고리즘 추가. base64, hex, latin1이 주로 사용. base64가 문자열이 가장 짧음
3.5.5.2 양방향 암호화
암호화된 문자열을 복호화할 수 있으며, 키(열쇠)가 사용.
객체 / 메서드 | 설명 |
---|---|
crypto.createCipheriv(알고리즘, 키, iv) |
암호화에 사용할 정보 추가. 사용 가능한 알고리즘 목록은 crypto.getCiphers()로 확인 가능 |
cipher.update(문자열, 인코딩, 출력 인코딩) |
암호화할 추가 정보. 보통 문자열은 utf8, 인코딩은 base64 를 많이 사용. |
cipher.final(출력 인코딩) |
출력 결과물의 인코딩을 넣으면 암호화가 완료. |
crypto.createDecipheriv(알고리즘, 키, iv) |
복호화에 사용. |
decipher.update(문자열, 인코딩, 출력 인코딩) |
암호화된 문장, 그 문장의 인코딩, 복호화할 인코딩 추가. cipher.update의 인코딩, 출력 인코딩의 순서를 바꿔서 넣는다. |
decipher.final(출력 인코딩) |
복호화 결과물의 인코딩을 넣는다. |
3.5.6 util
각종 편의 기능을 모아둔 모듈
util.deprecate
: 함수가 deprecate 처리되었음을 알린다.util.promisify
: 콜백 패턴을 프로미스 패턴으로 변경. async/await 패턴까지 사용할 수 있다.
3.5.7 worker_threads
노드에서 멀티 스레드 방식으로 작업할 수 있도록 하는 모듈
- Worker : new Worker() 로 현재 패일을 워커 스레드에서 실행시킬 수 있다.
- isMainThread : 현재 코드가 메인 스레드에서 실행되는지 확인
- parentPort : 워커일 때 부모와 소통하기 위해 사용.
- workerData : 워커일 때 부모로부터 원하는 데이터를 받을 수 있다.
3.5.8 child_process
노드에서 다른 프로그램을 실행하고 싶거나 명령어를 수행하고 싶을 때 사용
exec : 첫 번째 인수로 명령어를 넣는다.
spawn : 첫 번째 인수로 명령어를, 두 번째 인수로 옵션 배열을 넣는다.
3.5.9 기타 모듈들
모듈 | 설명 |
---|---|
assert |
값을 비교하여 프로그램이 제대로 동작하는지 테스트 |
dns |
도메인 이름에 대한 IP주소를 얻어내는 데 사용 |
net |
HTTP 보다 로우 레벨인 TCP나 IPC 통신을 할 때 사용 |
string_decoder |
버퍼 데이터를 문자열로 바꾸는 데 사용 |
tls |
TLS와 SSL에 관련된 작업을 할 때 사용 |
tty |
터미널과 관련된 작업을 할 때 사용 |
dgram |
UDP와 관련된 작업을 할 때 사용 |
v8 |
V8 엔진에 직접 접근할 때 사용 |
vm |
가상 머신에 직접 접근할 때 사용 |
3.6 파일 시스템 접근하기
fs모듈 : 파일 시스템에 접근하는 모듈.
readFile(파일 경로, 콜백 함수)
: 읽을 파일의 경로를 지정하고 콜백 함수의 매개 변수로 에러 또는 데이터를 받는다. 결과물은 버터 형식으로 제공되므로 toString()으로 문자열로 변환한다.
3.6.1 동기 메서드와 비동기 메서드
fs 모듈은 주로 동기 방식으로 사용 가능한 메서드가 많다.
readFileSync(문자열)
: 콜백 함수를 넣는 대신 직접 리턴 값을 받아온다. 다만 요청이 수백 개 이상 등어올 경우 성능에 문제가 생긴다.
3.6.2 버퍼와 스트림 이해하기
버퍼와 스트림 둘 다 파일을 읽거나 쓰는 방식에 사용.
버퍼
파일을 읽을 때 메모리에 파일 크기만큼 공간을 마련해두며 파일 데이터를 메모리에 저장한 뒤 사용자가 조작할 수 있도록 하는데, 이 때 메모리에 저장된 데이터가 버퍼.
Buffer 클래스를 이용하여 버퍼를 직접 다를 수 있다.
Buffer 메서드
- from(문자열) : 문자열을 버퍼로 변환
- toString(버퍼) : 버퍼를 다시 문자열로 변환
- concat(배열) : 배열 안 버퍼를 하나로 합친다
- alloc(바이트) : 빈 퍼버를 생성
스트림
버퍼를 작게 만든 후 여러 번으로 나눠 보내는 방식을 편리하게 만든 것
스트림 메서드
- createReadStream(파일 경로, 옵션 객체) : 읽기 스트림 생성
- createWriteStream(파일 경로) : createReadStream로 파일을 읽고 스트림을 전달 받을 수 있다.
- readStream : data,end,error 등의 이벤트 리스너를 붙여 사용.
- pipe : 스트림끼리 연결
3.6.3 기타 fs 메서드 알아보기
메서드 | 설명 |
---|---|
fs.access(경로, 옵션, 콜백) |
폴더나 파일에 접근할 수 있는지 체크 |
fs.mkdir(경로, 콜백) |
폴더를 만드는 메서드 |
fs.open(경로, 옵션, 콜백) |
파일의 아이디를 가져오는 메서드. 가져온 아이디를 사용해 fs.read나 fs.write 로 읽거나 쓸 수 있다. |
fs.rename(기존 경로, 새 경로, 콜백) |
파일의 이름을 바꾸는 메서드 |
fs.readdir(경로, 콜백) |
폴더 안의 내용물을 확인할 수 있다. |
fs.unlink(경로, 콜백) |
파일을 지울 수 있다. |
fs.rmdir(경로, 콜백) |
폴더를 지울 수 있다. |
3.6.4 스레드풀 알아보기
fs 모듈은 스레드풀을 사용하기 때문에 메서드를 여러 번 실행해도 백그라운드에서 동시에 처리할 수 있다.
node threadpool
로 스레드풀을 확인할 수 있으며, UV_TEREADPOOL_SIZE=숫자
를 입력함으로서 개수를 조절할 수 있다.
3.7 이벤트 이해하기
events모듈 메서드
메서드 | 설명 |
---|---|
on(이벤트명, 콜백) |
이벤트 이름과 이벤트 발생 시의 콜백을 연결. 연결 동작을 이벤트 리스닝이라고 부른다. |
addListener(이벤트명, 콜백) |
on 과 기능이 동일 |
emit(이벤트명) |
이벤트를 호출하는 메서드 |
once(이벤트명, 콜백) |
한 번만 실행되는 이벤트 |
removeAllListeners(이벤트명) |
이벤트에 연결된 모든 이벤트 리스너를 제거 |
removeListener(이벤트명, 리스너) |
이벤트에 연결된 리스너를 하나씩 제거 |
off(이벤트명, 콜백) |
노드 10에서 추가된 메서드, removeListener 와 기능 동일 |
listenerCount(이벤트명) |
현재 리스너가 몇 개 연결되어있는지 확인 |
3.8 예외 처리하기
예외 : 처리하지 못한 에러
- 프로미스를 사용할 때는 항상 catch를 붙여주는 것이 좋다.
3.8.1 자주 발생하는 에러들
에러 | 발생 이유 |
---|---|
node: command not found |
노드를 설치했지만 환경 변수가 제대로 설정되지 않은 경우 |
ReferenceError |
모듈 is not defined : 모듈을 require하지 않는 경우 |
Error: Cannot find module 모듈명 |
해당 모듈을 require했지만 설치하지 않은 경우 |
Error: Can't set headers after they are sent |
요청에 대한 응답을 두 번 이상 보낸 경우 |
FATAL ERROR: CALL_AND_RETRY_LAST Allocation faild - JvavScript heap out of memory |
코드를 실행할 때 메모리가 부족하여 스크립트가 정상 작동하지 않는 경우 |
UnhandlePromiseRejectionWarning: Unhandled promise rejection |
프로미스 사용 시 cath 메서드를 붙이지 않을 때 발생 |
EADDRINUSE 포트 번호 |
해당 포트 번호에 이미 다른 프로세스가 연결되어 있는 경우 |
EACCES 또는 EPERM |
노드가 작업을 수행하는 데 권한이 충분하지 않은 경우 |
EJSONPARSE |
package.json등의 JSON 파일에 문법 오류가 있는 경우 |
ECONNREFUSED |
요청을 보냈으나 연결이 성립하지 않을 경우 |
ETARGET |
package.json에 기록한 패키지 버전이 존재하지 않을 경우 |
ETIMEOUT |
요청을 보냈으나 응답이 일정 시간 내에 오지 않을 경우 |
ENOENT: no such file or directory |
지정한 폴더나 파일이 존재하지 않는 경우 |