본문 바로가기
Node.js

[Backend] 노드 기능

by Hangii 2023. 1. 26.

REPL

자바스크립트는 스크립트 언어라서 즉석에서 코드를 실행할 수 있다.

  • js에서는 REPL이라는 콘솔이 제공된다.
  • R(Read), E(Evaluate), P(Print), L(Loop)
  • Window에서는 명령 프롬프트, 맥/리눅스에서는 터미널에 node 입력하면 노드를 실행할 수 있다.

모듈 만들기

노드는 자바스크립트 코드를 모듈로 만들 수 있다.

  • 모듈: 특정한 기능을 하는 함수나 변수들의 집합
  • 모듈로 만들면 여러 프로그램에서 재사용이 가능하다.
  • node의 모듈 시스템(require, module.exports)은 js의 모듈 시스템(import, export)과 문법이 다르다.
  • require를 import ~ from ' '로, module.exports 를 export default로 대체할 수 있으나, 완벽히 일대일대응 되지는 않는다.

var.js

const odd = '홀수입니다';
const even = '짝수입니다';

//odd와 even을 여러 개의 파일에서 쓰고 싶은 경우, 매번 const odd = '홀수입니다';등을 작성하면 같은 코드를 계속 반복해야 하므로 비효율적이다. 이를 모듈로 만들어서 간편하게 사용할 수 있다.
//다른 파일에서 쓰고 싶은 변수들은 module.exports에 대입함으로써 넘겨줄 수 있다. []사용해 배열로 export해도 된다.
module.exports = {
    odd,  //객체임. 따라서 원래는 odd: odd,라고 써야하지만 최신 문법에서부턴 키와 값 변수가 같은 경우 한번만 써도 되도록 함.
    even,
}

 

func.js

const value = require('./var'); //현재 폴더 내의 var.js를 가져오겠다는 의미. require함수는 node에 내장되어 있다.
console.log(value);  //var.js에서 export했던 객체 값들이 출력될 것이다.

//터미널에 node func 입력하면 { odd: '홀수입니다', even: '짝수입니다' } 출력됨.

//구조분해 할당도 가능함.
const { odd, even } = require('./var');
function checkOddOrEven(number) {
    if (number % 2) {
        return odd;
    } else {
        return even;
    }
}

//module.exports는 한 파일 당 한 번만 사용할 수 있음에 주의하자.
module.exports = {
    checkOddOrEven, //새로 만든 함수를 다른 곳으로 넘기기
    odd,  //이미 넘겨받은 애를 다른 곳으로 또 넘겨줄 수도 있다.
    even,
}

 

index.js

const { odd, even } = require('./var');
const checkNumber = require('./func');  //checkOddOrEven을 가져오면서 새 변수명 설정.

function checkStringOddOrEven(str) {
    if (str.length % 2) {
        return odd;
    } else {
        return even;
    }
}

console.log(checkNumber(10));
console.log(checkStringOddOrEven('hello'));

 

global과 콘솔, 타이머

global : 노드의 전역 객체

  • 브라우저의 window같은 역할
  • 모든 파일에서 접근 가능
  • window처럼 생략도 가능(console, require도 global의 속성) 
    • 앞에서 알아본 require도 원래는 global.require이고 console.log도 원래 global.console.log인데 모두 앞의 global을 생략한 것이다.

 

global 속성 공유

권장하지는 않는 방법

  • global 속성에 값을 대입하면 다른 파일에서도 사용 가능
  • 그렇지만 모듈 대신 global을 사용하면 파일이 많아질 경우 헷갈리기 때문에 좋은 방법은 아니다.

 

console 객체

브라우저의 console 객체와 매우 유사하다.

  • console.time과 console.timeEnd를 사용해서 둘 사이에 있는 코드를 실행하는 데 걸리는 시간을 측정할 수 있다.
const { odd, even } = require('./var');
console.time('here'); //측정 시작 시간
function checkOddOrEven(number) {
    if (number % 2) {
        return odd;
    } else {
        return even;
    }
}
console.timeEnd('here'); //측정 종료 시간
module.exports = checkOddOrEven;
  • console.error: 에러 로깅
  • console.log: 평범한 로그
  • console.dir: 객체 로깅
  • console.trace: 함수 안에서 사용하면 호출 스택 로깅
  • console.table: 표처럼 로깅

 

타이머 메서드

set 메서드에 clear 메서드가 대응된다.

  • set 메서드의 리턴값(아이디)을 clear 메서드에 넣어 취소
  • setTimeout(콜백 함수, 밀리초): 주어진 밀리초(1000분의 1초) 이후에 콜백함수를 실행
  • setInterval(콜백 함수, 밀리초): 주어진 밀리초마다 콜백 함수를 반복 실행
  • setImmediate(콜백 함수): 콜백 함수를 즉시 실행

 

  • clearTimeout(아이디): setTimeout을 취소
  • clearInterval(아이디): setInterval을 취소
  • clearImmediate(아이디): setImmediate을 취소합
  • 다만, 취소하려면 타이머를 변수에 대입한 후 그 변수(예를 들면 hello)를 취소해야 한다.(clearInterval(hello) 이런 식으로)
setImmediate(()=> console.log('hi'))  //바로 실행됨.
setTimeout(()=>console.log('hi'), 0)  //윗줄과 같은 결과 출력이지만 실행 순서 면에서 헷갈리니 그냥 setImmediate를 사용하도록 하자.

 

__filename, __dirname

  • __filename: 현재 파일 경로
  • __dirname: 현재 폴더(디렉토리) 경로
  • node를 사용해 HDD나 SSD에 접근이 가능하다.

 

exports와 this

exports

module.exports = ~;는 하나의 값만을 export할 때 주로 사용하고, 2개 이상의 값을 export하고 싶은 경우에는 exports.odd = odd;, exports.even = even; 이런 식으로 사용한다. 

module.exports와 exports를 혼용해서 쓸 수 없음에 주의하자.

 

this

보통 js에서 this는 전역 객체를 가리킨다. node에서는 전역 객체는 global이니까 node의 this는 global인가? 싶기도 하겠지만 아니다. js 파일을 생성해서 console.log(this); 를 찍어보면 빈 객체가 출력된다. node에서는 function 안에 있는 this만 global이다. 전역 스코프의 this는 module.exports이다.

 

require의 특성

다른 파일의 값을 불러와서 사용하지는 않지만 그 파일을 실행하고 싶을 때는 require('./var');만 작성하면 된다.

require('./var');
console.log(require);

이렇게 작성한 후 터미널을 실행해보면 require에 대한 다양한 로그들이 출력되는 것을 볼 수 있다. js의 import는 가장 위에 위치해야 하지만 require는 항상 코드 가장 위에 올 필요는 없다.

 

require.main

require.main은 노드 실행 시 첫 모듈을 가리킨다.

 

require.cache

require('./var');을 여러 개의 파일에 작성했다고 가정하자. 처음 require했을 때는 var파일에서 직접 불러오지만, 두번재 require부터는 캐시된 정보를 불러오게 된다. HDD에서 값을 불러오는 것보다 메모리에서 불러오는 게 더 빠르기 때문에 이 방법을 사용한다. require.cache에는 한 번 require한 모듈에 대한 캐시 정보가 들어있다.

 

require.js

console.log('require가 가장 위에 오지 않아도 됩니다!');

module.exports = '저를 찾아보세요.';

require('./var');

console.log('require cache입니다.');
console.log(require.cache);
console.log('require.main입니다.');
console.log(require.main === module);
console.log(require.main.filename);

 

순환 참조

두 파일 dep1.js와 dep2.js가 다음과 같이 작성되었다고 가정하자.

dep1.js

const dep2 = require('./dep2');
console.log('require dep2', dep2);
module.exports = () => {
	console.log('dep2', dep2);
};

dep2.js

const dep1 = require('./dep1');
console.log('require dep1', dep1);
module.exports = () => {
	console.log('dep1', dep1);
};

dep1을 실행하면 dep2를 require하고, dep2는 다시 dep1을 require하는 상황이 발생한다. 이를 순환 참조라고 하는데, 순환 참조가 일어나면 컴퓨터가 제대로 일을 할 수 없다. 노드에서는 이런 상황을 방지하기 위해 순환 참조가 일어나면 dep1의 module.exports가 함수가 아니라 빈 객체가 되도록 변경한다. (무한 반복을 막기 위해)

하지만 무엇보다 코딩을 할 때 순환 참조하는 상황을 만들지 않는 것이 가장 좋다.

 

process

노드는 파일 시스템 뿐만 아니라 운영체제에도 접근이 가능하다.

[콘솔창]

>process.version: 설치된 노드의 버전 출력

>process.arch: 프로세서 아키텍처 정보 출력

>process.platform: 운영체제 플랫폼 정보 출력

>process.pid: 현재 프로세스 아이디 출력. 나중에 프로세스를 종료할 때 id 사용.

>process.uptime(): 프로세스가 시작된 후 흐른 시간 출력. 단위는 초.

>process.execPath: 노드의 경로 출력

>process.cwd(): 현재 프로세스가 실행되는 위치 출력. 자주 쓰임.

>process.cpuUsage(): 현재 cpu사용량 출력

 

process.env

시스템 환경 변수들이 들이있는 객체

  • 비밀키(데이터베이스 비밀번호, 서드파티 앱 키 등)를 보관하는 용도로도 쓰인다. process.env안에 중요한 정보들을 저장해두면 소스코드가 해킹당했을 경우에도 정보들이 드러나지 않는다.
  • 환경 변수는 process.env로 접근이 가능하다.
const secretId = process.env.SECRET_ID;
const secretCode = process.env.SECRET_CODE;
  • 일부 환경 변수는 노드 실행 시 영향을 미친다. 
  • e.g.) NODE_OPTIONS(노드 실행 옵션), UV_THREADPOOL_SIZE(스레드풀 개수)
    • max-old-space-size는 노드가 사용할 수 있는 메모리를 지정하는 옵션
NODE_OPTIONS=--max-old-space-size=8192  //node가 사용할 수 있는 메모리의 크기를 늘리는 코드.
UV_THREADPOOL_SIZE=8  //node에서 동시에 최대 8개의 코드를 돌리도록 설정.

 

process.exit

현재의 프로세스를 멈춤

  • 코드가 없거나 0이면 정상 종료
  • 이외의 코드는 비정상 종료를 의미함
  • 터미널에서 노드를 실행시킨 후에 종료하고 싶을 땐 process.exit(0)을 입력한다. 서버를 끄고 싶을 때 사용하는 코드이다.(많이 쓰이진 않음)
  • 서버 에러가 난 경우, 에러가 있음을 알리기 위해 process.exit(1)을 작성하기도 한다.

os

운영체제의 정보를 담고 있는 node 모듈이다.

const os = require('os');  //os라는 파일은 직접 만들지 않아도 node에서 제공된다.(이미 모듈로 만들어둔 것임)
  • 모듈은 require로 가져온다. 내장 모듈이라 경로 대신 이름만 적어줘도 된다.

os.js

const os = require('os');

console.log('운영체제 정보-----------------------------');
console.log('os.arch():', os.arch());
console.log('os.platform():', os.platform());
console.log('os.type():', os.type());
console.log('os.uptime():', os.uptime());
console.log('os.hostname():', os.hostname());   //컴퓨터 이름 출력
console.log('os.release():', os.release());

console.log('경로--------------------------------------');
console.log('os.homedir():', os.homedir());
console.log('os.tmpdir():', os.tmpdir());

console.log('cpu 정보----------------------------------');
console.log('os.cpus():', os.cpus());  //cpu 정보(core 갯수, 속도 등)
console.log('os.cpus().length:', os.cpus().length);

console.log('메모리 정보-------------------------------');
console.log('os.freemem():', os.freemem());  //free memory 정보
console.log('os.totalmem():', os.totalmem());  //총 memory 정보

 

os 모듈 메서드

[콘솔창]

>os.arch(): process.arch와 동일

>os.platform(): process.platform과 동일

>os.type(): 운영체제의 종류 출력

>os.uptime(): 운영체제 부팅 이후 흐른 시간(초) 출력. process.uptime()은 노드의 실행 시간이었음에 주의할 것.

>os.hostname(): 컴퓨터의 이름을 보여줌

>os.release(): 운영체제의 버전을 보여줌

>os.homedir(): 홈 디렉토리 경로를 보여줌

>os.tmpdir(): 임시 파일 저장 경로를 보여줌

>os.cpus(): 컴퓨터의 코어 정보를 보여줌

>os.freemem(): 사용 가능한 메모리(RAM)을 보여줌

>os.totalmem(): 전체 메모리 용량을 보여줌

 

https://nodejs.org/dist/latest-v19.x/docs/api/os.html#oshomedir 공식 문서에서 노드가 제공하는 내장 모듈에 대해 자세히 알 수 있다. 

 

OS | Node.js v19.5.0 Documentation

Source Code: lib/os.js The node:os module provides operating system-related utility methods and properties. It can be accessed using: const os = require('node:os'); os.EOL# Added in: v0.7.8 The operating system-specific end-of-line marker. \n on POSIX \r\n

nodejs.org

 

path

폴더와 파일의 경로를 쉽게 조작하도록 도와주는 모듈

  • 운영체제별로 경로 구분자가 다르다.(Windows: \ , POSIX(Mac + Linux): / )
  • path.join(__dirname, '..', '/var.js');  //path.join은 절대경로(/) 표시를 무시하고, path.join(__dirname, '..', 'var.js'); 와 같은 결과를 출력한다. C:\Users\folder1\folder2\nodejsStudy\var.js 등의 결과가 출력될 것이다.
  • path.resolve(__dirname, '..', '/var.js');  //path.resolve는 절대경로(/)를 최우선으로 존중하고, 나머지 앞부분을 무시한다. 따라서 C:\var.js 가 출력될 것이다.

 

path 모듈 메서드

[콘솔창]

>path.sep: 경로의 구분자. Windows는 \, POSIX는 /

>path.delimiter: 환경 변수의 구분자. process.env.PATH를 입력하면 여러 개의 경로가 이 구분자로 구분되어 있다. WIndows는 세미콜론(;)이고 POSIX는 콜론(:)이다.

>path.dirname(경로): 파일이 위치한 폴더 경로를 보여줌

>path.extname(경로): 파일의 확장자를 보여줌

>path.basename(경로, 확장자): 파일의 이름(확장자 포함)을 보여줌. 파일의 이름만 표시하고 싶다면 basename의 두번쨰 인자로 파일의 확장자를 넣어주면 됨.

>path.parse(경로): 파일 경로를 root, dir, base, ext, name으로 분리함

>path.format(객체): path.parse()한 객체를 파일 경로로 합침

>path.normalize(경로): \나 /를 실수로 여러 번 사용했거나 혼용했을 때, 정상적인 경로로 변환해줌

>path.isAbsolute(경로): 파일의 경로가 절대경로인지 상대경로인지 true나 false로 알려줌

>path.relative(경로, ...): 여러 인자를 넣으면 하나의 경로로 합쳐줌. 상대경로인..(부모 디렉토리)와 .(현 디렉토리)도 알아서 처리해줌.

>path.resolve(경로, ...): path.join()과 비슷하지만 차이가 있다. (차이점은 Note에서 설명)

 

  • \\와 \ 차이: \는 윈도우 경로 구분자, \\는 자바스크립트 문자열 안에서 사용(\가 특수문자라서 \\로 이스케이프 해준 것)
  • 윈도우에서 POSIX path를 쓰고 싶다면: path.posix 객체 사용
  • POSIX에서 윈도우 path를 쓰고 싶다면: path.win32 객체 사용

'Node.js' 카테고리의 다른 글

[Backend] 패키지 매니저  (0) 2023.01.30
[Backend] http 모듈로 서버 만들기  (0) 2023.01.30
[Backend] 프로미스  (1) 2023.01.26
비구조화 할당  (0) 2023.01.26
화살표 함수  (0) 2023.01.25

댓글