Node.js 기능
REPL 사용하기
- JS는 스크립트 언어
- 컴파일 하지 않아도 코드실행 가능
- REPL(Read Eval Print Loop)
node로 REPL 실행. ctrl+D로 종료- 한두 줄 코드 실행하기는 좋음
JS 파일 실행하기
- 아무 위치에서나 실행 가능
helloWorld.js
jsfunction helloWorld() {
console.log('Hello World');
helloNode();
}
function helloNode() {
console.log('Hello Node');
}
helloWorld();
- node [JS 파일 경로]
.js생략 가능node helloWorld
모듈로 만들기
- 모듈로 만들어두면 여러 프로그램에서 재사용 가능
- 브라우저의 모듈은 크롬 60부터 사용가능, 하지만 아직 사용은 비추천. ex) IE
var.js
jsconst odd = '홀수입니다';
const even = '짝수입니다';
module.exports = {
odd,
even
};
func.js
jsconst {odd, even} = require('./var');
function checkOddOrEven(num) {
if (num % 2) { // 홀수면
return odd;
}
return even;
}
module.exports = checkOddOrEven;
index.js
jsconst {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');
- 모듈로부터 값을 불러올 때 변수 이름을 다르게 지정할 수 있음
checkOddOrEven이checkNumber로 사용*.mjsES2015에 도입된 모듈 시스템.node --experimental-modules 파일명처럼 옵션 필요
노드 내장 객체 알아보기
- 내장 객체와 내장 모듈
- 브라우저의
window객체와 비슷
global
-
전역객체
-
생략 가능
global.require->requireglobal.console->console
-
node.js에는 DOM(Document Object Model), BOM(Browser Object Model)이 없기 때문에
window,document사용할 수 없음 -
global에는 수십 가지 속성이 담겨 있음 -
globalA.js
jsmodule.exports = () => global.message;
globalB.js
jsconst A = require('./globalA');
global.message = '안녕하세요';
console.log(A());
golbalB에 넣은global.message값을globalA에서 접근 가능
console
console디버깅을 위해 사용console.js
타이머
timer.js
__filename, __dirname
filename.js
module, exports
- exports 객체로도 모듈 생성 가능
var.js
jsexports.odd = '홀수입니다';
exports.even = '짝수입니다';
console.log(module.exports === exports)
process
- 현재 실행되고 있는 노드 프로세스에 대한 정보를 담고 있음
process.env
- 시스템 환경 변수
- API 키를 코드 대신 환경변수에 설정해서 활용
process.nextTick(콜백)
- 이벤트 루프가 다른 콜백 함수들보다
nextTick의 콜백 함수를 우선으로 처리하도록 만듬 nextTick.jsprocess.nextTick은setImmediate나setTimeout보다 먼저 실행됨.- 코드 맨 밑에
Promise를 넣은 것은resolve된Promise도nextTick처럼 다른 콜백들보다 우선시되기 때문 process.nextTick과Promise를마이크로태스크(microtask)라고 따로 구분지어 부름
process.exit(코드)
- 실행중인 노드 프로세스 종료
exit.js
내장 모듈 사용하기
- 운영체제 정보에도 접근, 클라이언트가 요청한 주소에 대한 정보도 가져올 수 있음
- 노드 버전마다 차이가 있음
os
os.js
path
path.js
url
url.jssearchParams.js
querystring
querystring.js
crypto
- 다양한 방식의 암호화 도와주는 모듈
단방향 암호화
- 비밀번호 등 복호화가 필요하지 않은 경우
- 암호화된 문자열로만 비교
hash.jscrypto.createHash('sha512'):,md5,sha1sha256,sha512update(문자열): 비밀번호 등 변환할 문자열digest(인코딩):base64,hex,latin1
pbkdf2.js- node.js에서 기본 지원
- salt라고 불리는 문자열을 붙인 후 해시 알고리즘을 반복 적용해서 암호화
randomBytes(): 64바이트 길이의 문자열 생성saltcrypto.pbkdf2(비밀번호, salt, 반복횟수, 출력바이트, 해시알고리즘)
양방향 암호화
- 전화번호, 이메일 등 복호화가 필요한 경우
- key 사용해서 암호화하고 같은 key 사용해서 복호화
cipher.jscrypto.createCipher(알고리즘, 키)crypto.getCiphers(): 사용 가능한 알고리즘 목록
text> crypto.getCiphers()
[ 'aes-128-cbc',
'aes-128-cbc-hmac-sha1',
'aes-128-cbc-hmac-sha256',
'aes-128-ccm',
'aes-128-cfb',
'aes-128-cfb1',
'aes-128-cfb8',
'aes-128-ctr',
'aes-128-ecb',
'aes-128-gcm',
'aes-128-ofb',
'aes-128-xts',
'aes-192-cbc',
'aes-192-ccm',
'aes-192-cfb',
'aes-192-cfb1',
'aes-192-cfb8',
'aes-192-ctr',
'aes-192-ecb',
'aes-192-gcm',
'aes-192-ofb',
'aes-256-cbc',
'aes-256-cbc-hmac-sha1',
'aes-256-cbc-hmac-sha256',
'aes-256-ccm',
'aes-256-cfb',
'aes-256-cfb1',
'aes-256-cfb8',
'aes-256-ctr',
'aes-256-ecb',
'aes-256-gcm',
'aes-256-ofb',
'aes-256-xts',
'aes128',
'aes192',
'aes256',
'bf',
'bf-cbc',
'bf-cfb',
'bf-ecb',
'bf-ofb',
'blowfish',
'camellia-128-cbc',
'camellia-128-cfb',
'camellia-128-cfb1',
'camellia-128-cfb8',
'camellia-128-ecb',
'camellia-128-ofb',
'camellia-192-cbc',
'camellia-192-cfb',
'camellia-192-cfb1',
'camellia-192-cfb8',
'camellia-192-ecb',
'camellia-192-ofb',
'camellia-256-cbc',
'camellia-256-cfb',
'camellia-256-cfb1',
'camellia-256-cfb8',
'camellia-256-ecb',
'camellia-256-ofb',
'camellia128',
'camellia192',
'camellia256',
'cast',
'cast-cbc',
'cast5-cbc',
'cast5-cfb',
'cast5-ecb',
'cast5-ofb',
'des',
'des-cbc',
'des-cfb',
'des-cfb1',
'des-cfb8',
'des-ecb',
'des-ede',
'des-ede-cbc',
'des-ede-cfb',
'des-ede-ofb',
'des-ede3',
'des-ede3-cbc',
'des-ede3-cfb',
'des-ede3-cfb1',
'des-ede3-cfb8',
'des-ede3-ofb',
'des-ofb',
'des3',
'desx',
'desx-cbc',
'id-aes128-CCM',
'id-aes128-GCM',
'id-aes128-wrap',
'id-aes192-CCM',
'id-aes192-GCM',
'id-aes192-wrap',
'id-aes256-CCM',
'id-aes256-GCM',
'id-aes256-wrap',
'id-smime-alg-CMS3DESwrap',
'idea',
... 19 more items ]
util
util.js
파일 시스템 접근하기
const fs = require('fs')readme.txtreadFile.jsreadFile()결과는 버퍼(메모리의 데이터) 형식,.toString()을 통해서 문자열로 변환
writeFile.js
동기 메서드와 비동기 메서드
readme2.txtasync.jssync.jsasyncOrder.js
버퍼와 스트림 이해하기
- 로딩중일 때 버퍼링, 송출할 때는 스트리밍
- 버퍼를 직접 다루는 클래스 :
Buffer buffer.jsfrom(문자열): 문자열을 버퍼로 변환toString(인코딩): 버퍼를 다시 문자열로base64,hex인코딩 가능concat(배열): 배열 안에 든 버퍼들을 하나로 합침alloc(바이트): 빈 버퍼 생성
- 버퍼의 크기를 작게 만들어서 여러 번에 나눠서 보내는 방식
- 1MB 메모리로 100MB 파일 전송
- 이 작업을 편리하게 만든 것이 스트림
readme3.txtcreateReadStream.jscreateWriteStream.jsreadme4.txtpipe.jsgzip.js
기타 fs 메서드
fsCreate.js
jsconst fs = require('fs');
fs.access('./folder', fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK, (err) => {
if (err) {
if (err.code === 'ENOENT') {
console.log('폴더 없음');
fs.mkdir('./folder', (err) => {
if (err) {
throw err;
}
console.log('폴더 만들기 성공');
fs.open('./folder/file.js', 'w', (err, fd) => {
if (err) {
throw err;
}
console.log('빈 파일 만들기 성공', fd);
fs.rename('./folder/file.js', './folder/newfile.js', (err) => {
if (err) {
throw err;
}
console.log('이름 바꾸기 성공');
});
});
});
} else {
throw err;
}
} else {
console.log('이미 폴더 있음');
}
});
fsDelete.js
jsconst fs = require('fs');
fs.readdir('./folder', (err, dir) => {
if (err) {
throw err;
}
console.log('폴더 내용 확인', dir);
fs.unlink('./folder/newFile.js', (err) => {
if (err) {
throw err;
}
console.log('파일 삭제 성공');
fs.rmdir('./folder', (err) => {
if (err) {
throw err;
}
console.log('폴더 삭제 성공');
});
});
});
copyfile.js
jsconst fs = require('fs');
fs.copyFile('readme4.txt', 'writeme4.txt', (error) => {
if (error) {
return console.error(error);
}
console.log('복사 완료');
});
이벤트 이해하기
event.js
jsconst EventEmitter = require('events');
const myEvent = new EventEmitter();
myEvent.addListener('event1', () => {
console.log('이벤트 1');
});
myEvent.on('event2', () => {
console.log('이벤트 2');
});
myEvent.on('event2', () => {
console.log('이벤트 2 추가');
});
myEvent.emit('event1');
myEvent.emit('event2');
myEvent.once('event3', () => {
console.log('이벤트 3');
});
myEvent.emit('event3');
myEvent.emit('event3');
myEvent.on('event4', () => {
console.log('이벤트 4');
});
myEvent.removeAllListeners('event4');
myEvent.emit('event4');
const listener = () => {
console.log('event5');
}
myEvent.on('event5', listener);
myEvent.removeListener('event5', listener);
myEvent.emit('event5');
console.log(myEvent.listenerCount('event2'));
on(이벤트명, 콜백)addListener(이벤트명, 콜백)emit(이벤트명)once(이벤트명, 콜백)removeAllListeners(이벤트명)removeListener(이벤트명, 리스너)off(이벤트명, 콜백)listenCount(이벤트명)
예외 처리하기
-
예외 처리 못하면 Node 프로세스 멈춤. 예) 서버 다운
-
멀티 스레드 프로그램에서 하나가 멈추면 다른 스레드가 대신
-
싱글 스레드인 노드는 전체 서버가 멈춘다는 의미
-
예기치 못한 에러 처리하는 기술 필수
-
문법상의 에러 없다고 가정 - 실제 배포용 코드에 문법 에러가 있다는 것은 말이 안됨
-
좋은 에디터, 좋은 문법 검사 도구
-
error1.js
jssetInterval(() => {
console.log('시작');
try {
throw new Error('서버를 고장내주마!');
} catch (err) {
console.error(err);
}
}, 1000);
error2.js
jsconst fs = require('fs');
setInterval(() => {
fs.unlink('./abcdefg.js', (err) => {
if (err) {
console.error(err);
}
});
}, 1000);
-
없는 파일 지우지만, 내장 모듈의 에러는 실행 중인 프로세스를 멈추지 않음
-
error3.js
jsprocess.on('uncaughtException', (err) => {
console.error('예기지 못한 에러', err);
});
setInterval(() => {
throw new Error('서버를 고장내주마!');
}, 1000);
setTimeout(() => {
console.log('실행됩니다.')
}, 2000);
uncaughtException이벤트 리스너로 모든 에러 처리 가능- 하지만 노드 공식 문서에서는 최후의 수단으로 권함
- 에러 발생시 철저히 기록하는 습관과 주기적 확인과 보완