NodeJS 기초 개념과 내장 모듈에 관하여

22366 단어 nodejsnodejs


🔎 NodeJS 이해하기

노드JS는 이벤트기반, 논블로킹 I/O를 사용한다. npm은 노드의 가장 큰 오픈 소스 라이브러리 생태계이다. npm에서 다운 받아 사용하는 모듈들을 서드파티라고 한다.

노드 JS는 정확하게 자바스크립트의 런타임을 의미한다. 런타임이란 어떤 언어가 돌아가는 환경을 말하는데 원래 자바스크립트의 런타임은 웹브라우저가 유일했지만 현재는 nodeJS를 통해 브라우저 외의 환경에서도 사용할 수 있게 되었다.


이벤트기반

이벤트기반이라는 것은 이벤트가 발생할 때 미리 저장해둔 작업을 수행하는 방식이다. 이벤트 기반의 핵심은 이벤트루프이다.

이는 다른기록공간에 더 자세하게 정리를 해두었다.

간단하게는 이벤트 발생 시 백그라운드가 이벤트 리스너에 등록한(된) 콜백함수를 테스크큐에 넣는다. 그리고 이벤트루프가 테스크큐의 함수를 콜스택으로 옮기고 콜백함수의 동작이 이루어진다고 알면된다.

이벤트루프는 콜스택이 비어있을 때만 테스크큐의 함수를 옮겨주기 때문에 setTimeout으로 3초를 지정해놨더라도 콜스택에 너무 많은 함수들이 쌓여있으면 3초가 지나도 setTimeout에 전달한 콜백함수를 실행해주지 않을 수도 있다.


논블로킹I/O

논블로킹IO는 이벤트루프를 적극 활용한 방법이다. 헤비하고 오래걸리는 함수를 백그라운드로 보내놓고 자바스크립트는 다른 코드를 먼저 처리한다. 그 동안 백그라운드는 헤비한 함수를 처리하고 테스크큐에 콜백을 올려놓는다. 이벤트루프는 자바스크립트의 콜스택이 비워질 때를 상시 체크하여 테스크큐에 올라온 헤비한 함수의 콜백을 콜스택으로 넣어줄 수 있다. 즉, 이전 작업의 완료를 기다리지 않고 다음 작업을 수행하는 것이 논블로킹 방식이다.

그렇다면 IO는 뭘까? I/O는 input과 output을 의미한다. 자바스크립트는 싱글스레드이기 때문에 모든 코드에서 시간적이득을 볼 수 있는 것은 아니고 주로 IO작업에서 시간 이득을 얻게된다. IO작업은 파일 시스템이나 네트워크 요청같은 작업으로 이러한 작업들은 OS에게 맡기고 다음 코드를 실행하는 방식으로 동작할 수 있기 때문이다. 이렇게 되면 OS는 작업을 요청받아도 노드를 막지 않아서 노드는 다음 동작을 수행한다. 만약 OS가 노드를 막았다면 그것은 블로킹 방식이고 노드는 OS가 작업을 완료할 때 까지 기다려줘야 한다.

Nodejs의 표준라이브러리의 모든 I/O메서드는 논블로킹인 비동기 방식을 제공한다. 그래서 fs모듈을 사용하면 비동기함수를 이용하게 되는 것이며 같은 작업을 블로킹 메서드로 제공하는 것들은 메서드 이름의 뒤에 Sync가 붙여서 사용할 수 있게한다.

노드는 싱글스레드, 논블로킹 모델을 사용하기 때문에 컴퓨터 자원을 적게 사용한다는 장점이 있지만 CPU코어를 여전히 하나밖에 사용하지 못하는 단점도 있다.


학습에서의 장점

노드에는 웹서버가 내장되어 있다. 다른 언어들은 아파치나 엔진엑스를 설치해야 하며 추가로 톰캣을 설치하기도 한다. 때문에 웹서버와 was사용법을 또 학습해야한다. 이런면에서 노드는 처음 서버를 공부할 때 유리하다. 하지만 결국 더 성장한 개발자가 되고 더 큰 서비스를 만드려면 결국에는 웹서버를 노드와 연결하게 되지만 처음부터 거기에 얽매이지 않을 수 있는 것이 장점이다.




🔎 내장 객체

global

global 객체에 프로퍼티를 추가하면 전혀 다른 파일에서 전역적으로 사용할 수 있다.

global.greeting = "how are you?"
console.log(greeting) //how are you?

타이머

global 객체 안에 타이머 기능을 제공하는 함수인 setTimeout, setInterval, setImmediate가 들어있다.

  • setTimeout(콜백 함수, 밀리초) : 주어진 밀리초(1000분의 1초) 이후에 콜백 함수를 실행합니다.
  • setInterval(콜백 함수, 밀리초) : 주어진 밀리초마다 콜백 함수를 반복 실행합니다.
  • setImmediate(콜백 함수) : 콜백 함수를 즉시 실행합니다.
const timeout = setTimeout(() => {
console.log('1.5초 후 실행');
}, 1500);

const interval = setInterval(() => {
console.log('1초마다 실행');
}, 1000);

const timeout2 = setTimeout(() => {
console.log('실행되지 않습니다');
}, 3000);

setTimeout(() => {
clearTimeout(timeout2);
clearInterval(interval);
}, 2500);

const immediate = setImmediate(() => {
console.log('즉시 실행');
});

const immediate2 = setImmediate(() => {
console.log('실행되지 않습니다');
});

clearImmediate(immediate2);

출처 : nodejs교과서 by 조현영

위 예제를 실행했을 때 콘솔에 어떻게 출력될지 예상해보자

즉시 실행
1초마다 실행
1.5초 후 실행
1초마다 실행

함수표현식 선언은 함수를 즉시 실행한다.

백그라운드에 전달되어 정해진 시간이 지나면 테스큐에 콜백함수를 전달한다.
하지만 그 시간이 지나기전에 삭제함수가 들어있는 콜백함수가 먼저 테스크큐에 전달되고 콜스택에 먼저올라가게 되면 타이머콜백함수는 파괴된다.

immediate의 경우 콜백함수가 백그라운드에 전달됨과 동시에 clearImmediate가 콜스택에 들어온다. immediate의 콜백함수가 테스크큐에 전달되었든 되지 않았든 콜스택의 clearImmediate가 사라지긴 전엔 콜스택으로 넘어올 수 없으며 clearImmediate가 동작해서 콜스택에서 사라질 때는 immediate의 콜백함수도 파괴되므로 콘솔에 출력되는 것은 없다.


process

  • process.env : 서비스의 중요한 키를 저장하는 공간으로 사용
  • process.nextTick(콜백) : 이벤트 루프가 다른 콜백 함수들보다 nextTick의 콜백 함수를 우선으로 처리
    • nextTick의 콜백은 마이크로태스크큐에 들어가서 태스크큐보다 우선순위를 가진다.
    • resolve된 Promise도 태스크큐가 아닌 마이크로태스크큐로 전달된다.
  • process.exit(코드) : 실행중인 노드 프로세스를 강제 종료



🔎 내장 모듈

OS

노드는 os 모듈에 정보가 담겨 있어 정보를 가져올 수 있다.

  • os.type(): 운영체제의 종류
  • os.uptime(): 운영체제 부팅 이후 흐른 시간(초)
  • os.hostname(): 컴퓨터의 이름
  • os.release(): 운영체제의 버전
  • os.homedir(): 홈 디렉터리 경로
  • os.tmpdir(): 임시 파일 저장 경로
  • os.cpus(): 컴퓨터의 코어 정보
  • os.freemem(): 사용 가능한 메모리(RAM)
  • os.totalmem(): 전체 메모리 용량

path

  • 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(경로, ...): 여러 인자를 넣으면 하나의 경로로 합침

url

인터넷 주소를 쉽게 조작하도록 도와주는 모듈이다.

const url = require("url")
const URL = url.URL
const naver = new URL('https://search.shopping.naver.com/search/category?catId=50000174')

console.log("naver url module:", naver)
console.log("------------------------------")
console.log("naver url: ", url.format(naver))
naver url module: URL {
  href: 'https://search.shopping.naver.com/search/category?catId=50000174',
  origin: 'https://search.shopping.naver.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'search.shopping.naver.com',
  hostname: 'search.shopping.naver.com',
  port: '',
  pathname: '/search/category',
  search: '?catId=50000174',
  searchParams: URLSearchParams { 'catId' => '50000174' },
  hash: ''
}
------------------------------
naver url:  https://search.shopping.naver.com/search/category?catId=50000174

출처 : nodejs교과서 by 조현영


버퍼와 스트림

파일을 전송하기 위해서 조금씩 나눠서 보내는 것을 스트리밍이라 한다.
스트리밍하는 데이터를 재생할 수 있을 만큼 모으는 것을 버퍼링이라고 한다.

스트리밍하는 데이터 즉, 쪼개진 데이터는 청크라고 부른다.

용량이 큰 파일을 읽을 때 한번에 읽으려 한다면 파일이 전부 가져와질 동안 빈 화면을 쳐다봐야한다. 이때 버퍼와 스트림을 사용해서 가져온 데이터라도 먼저 읽을 수 있도록 하는 것이 버퍼와 스트림이다.

const fs = require("fs")

result = []

fs.createReadStream('./test.txt', {
  highWaterMark: 8,
  encoding: 'utf-8'
}).on('data', (chunk)=>{
  result.push(chunk)
  console.log(chunk)
}).on('end', ()=>{
  console.log("------스트리밍결과-------")
  console.log(result.join(''))
})
hello, n
ice to m
eet you.

how are
 you?
I'
am fine,
 thank y
ou.
and 
you?
------스트리밍결과-------
hello, nice to meet you.
how are you?
I'am fine, thank you.
and you?

출처 : nodejs교과서 by 조현영

이런식으로 8바이트씩 데이터를 읽어오도록 스트리밍을 만들 수 있다.


이벤트

어떤 상황이 발생했을 때 그것에 반응하는 함수를 만들어줄 수 있다.
이벤트는 만들 수 있고 호출할 수 있고 삭제할 수 있다.

const EventEmitter = require('events')
const emitter = new EventEmitter()

emitter.on('Do greeting!', (name)=>{
  console.log(`how are you, ${name}?`)
})
emitter.on('Do greeting!', ()=>{
  console.log("I'm fine, and you?")
})

emitter.emit('Do greeting!', "james")
how are you, james?
I'm fine, and you?

출처 : nodejs교과서 by 조현영

좋은 웹페이지 즐겨찾기