# Nodejs란?
## nodeJS란 서버???
- nodejs 자체가 웹서버가 아니고 <br>
nodejs는 js를 사용해서 사용해서 서버 측에 코드들을 <br>작성하고 서버를 구축할 수 있게 도와주고 <br>
개발 생산성을 위해 npm을 통해 모듈을 제공한다.
## npm(node pacakage manager)란?
- 개발자들이 작성한 자신의 모듈을 공유할 수 있는 <br>패키지 저장소 npm을 사용하면 모듈을 쉽게 설치받아서 사용할 수 있다.<br>
node.js가 개발된 이유는 웹서버 개발을 하기위해서도 있지만 <br>방대한 오픈소스 생태계를 구축하기 위해서 개발자들이 편리하게 <br>
개발할 수 있게 개발 생산성을 향상 시켜주기 위해서.
## chrome v8 javascript
- chrome V8 javascript 엔진으로 `build`된
<br>서버 측 자바스크립트 런타임 환경 <br>
브라우저와 런타임환경이 다릅니다.
- build가 되었다는 건 구글에서 개발한 v8 javascript 엔진을 사용해서 build를 한다. <br>
build라는건 코드를 컴파일러를 통해 실행파일로 변환하는 작업이라고 보면됨
- 구글에서 개발한 v8 javascript 엔진은 2008년도 <br> 오픈소스로 공개하고 구글에서 개발한 <br>
js엔진을 사용하고 `비동기 I/O` 와 `이벤트 기반의 아키텍쳐`를 채택해서 속도가 빠르고 성능이 좋다.
## nodeJs의 블로킹과 논블로킹
- nodejs에서 `비동기 I/O` 작업을 진행하는 동안 또 다른 작업을 실행 할 수 있다. (nodeJS의 장점)
- I/O 작업이 완료될 떄 까지 기다리면서 다른 코드를 또 실행 시킬 수 있다. <br>
Input/Output:파일 시스템 (브라우저에서 파일을 조작할 순 없다.) 네트워크,디스크 등 <br>
데이터를 읽거나 쓰거나 하는 작업을(무거운 작업들)
- 블로킹이란 한 작업이 끝날 때 까지 다른 작업을 수행하지 않는것 <br>
블로킹 I/O 작업은 수행하는 동안 다른 코드의 실행이 중단된다.
- 논블로킹이란 I/O 작업을 기다리는 동안 다른 코드들을
실행할 수 있게 하는것 <br>
nodejs는 모든 I/O 작업은 비동기적으로 실행되고<br>
블로킹을 하지 않는다.
## nodejs의 이벤트 기반의 아키텍쳐
- nodejs 가장 큰 특징으로 이벤트 기반의 아키텍처가 있다. <br>이벤트 기반의 프로그래밍은 이벤트가 발생하면 콜백 함수를 실행시키는 방식 <br>
이벤트 기반의 프로그래밍을 작성하면 비동기식 처리가 가능하고 <br>좋은 성능과 확장성을 가질 수 있다.
- 이벤트 기반
<br>이벤트를 실행시키면 이벤트로 등록한 작업을 수행하는것
<br>우리가 자바스크립트에서 클릭 같은 이벤트에 콜백함수를 작성해놓고 <br>이벤트 기반의 특정 이벤트가 발생하면 등록시킨 콜백함수를 호출해서 실행 시킨다.
<br> 이런 내용을 `이벤트 리스너에 콜백함수를 등록한다.`
- nodejs는 이벤트가 발생하면 이벤트에 등록된 콜백 함수를 호출하고 이벤트를 다 처리하면 <br>
다음 이벤트 발생까지 대기한다.
```mermaid
graph TD;
A[nodejs]-- 이벤트 리스너와 콜백 함수 등록 -->D((이벤트 리스너));
D -- 이벤트를 수신 --> B[이벤트]
B -- 이벤트 리스터 호출 --> D
D -- 콜백 함수 호출 --> C[콜백함수]
C -- 작업을 수행 --> A
// nodejs설치 해봅시다
// 설치 버전 확인
// node -v
// nodejs의 Repl
// 읽기 -해석(실행) - 출력 -반복
//REPL(read-eval-print-loop)은 콘솔 환경에서
// 코드를 입력하면 즉시 실행해서 결과를 반환해주는 인터페이스
// node.js의 코드를 test하고 실행할 수 있도록 해주는 대화형 콘솔
// 레포라는 모드에 들어가 보자
// 터미널 창을 열고
// node만 써주면 됩니다.
// 레포 모드에서 test코드를 작성해보자
const str='hello world';
console.log(str)
// 출력된 값은 'hello nodejs'이렇게 나오고
// 함수의 반환값이 다음으로 출력되는데 undefined
// console.log(str)함수의 반환값이 undefined이기 때문!
// 그래서 helloworld 나오고 undefined나오는거
// 자바 스크립트로 브라우저 창을 만들고 볼 때는 런타임 환경
// node의 런타임 환경
// 실행되고 있는 환경이 다르다
// 브라우저에서 실행하는 console.log와 node.js에서 실행하는 console.log는
// 내용이 비슷한거지 같은 친구가 아니다.
// 브라우저에서는 this 전역객체가 window였고
// node 런타임 환경에서 this의 전역객체가 global
// node로 파일을 실행해서 응용프로그램으로 만들어보자
// 파일 실행 모드
// node 구문 뒤에 파일의 경로를 작성해 주면 된다.
// nodejs의 내장 모듈
// nodejs에서 미리 만들어 놓은 모듈을 내장 모듈이라고 해요.
// require에서 모듈경로와 파일명을 적는게 아니라
// 모듈의 이름만 필요
// 운영체제
const os = require("os");
console.log(os);
//nodejs의 내장 객체
// node의 전역객체에는 global 객체 우리가 js에서 보던 window 처럼
// 전역 객체가 있어요
// 런타임 환경이 다르기 때문에 전역 객체도 다르다.
// 자바스크립트에 this를 작성하면 module.exports가 나옴
// 참조가 들어가기 때문에 다르지 않을까?
// nodejs의 모듈의 실행 컨텍스트와 전역 컨텍스트가 다르기 때문에
// nodejs에서는 모듈은 각각의 파일 스코프를 가지고 있기 때문에 this는 모듈 자체를 가리킨다.
다음과 같이 os에 대한 정보가 나온다.
💡{
arch: [Function: arch] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
cpus: [Function: cpus],
endianness: [Function: endianness] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
freemem: [Function: getFreeMem] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
getPriority: [Function: getPriority],
homedir: [Function: __node_internal_checkError] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
hostname: [Function: __node_internal_checkError] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
loadavg: [Function: loadavg],
networkInterfaces: [Function: networkInterfaces],
platform: [Function: platform] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
release: [Function: getOSRelease] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
setPriority: [Function: setPriority],
tmpdir: [Function: tmpdir] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
totalmem: [Function: getTotalMem] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
type: [Function: getOSType] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
userInfo: [Function: userInfo],
uptime: [Function: getUptime] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
version: [Function: getOSVersion] {
[Symbol(Symbol.toPrimitive)]: [Function (anonymous)]
},
constants: [Object: null prototype] {
UV_UDP_REUSEADDR: 4,
dlopen: [Object: null prototype] {
RTLD_LAZY: 1,
RTLD_NOW: 2,
RTLD_GLOBAL: 8,
RTLD_LOCAL: 4
},
errno: [Object: null prototype] {
E2BIG: 7,
EACCES: 13,
EADDRINUSE: 48,
EADDRNOTAVAIL: 49,
EAFNOSUPPORT: 47,
EAGAIN: 35,
EALREADY: 37,
EBADF: 9,
EBADMSG: 94,
EBUSY: 16,
ECANCELED: 89,
ECHILD: 10,
ECONNABORTED: 53,
ECONNREFUSED: 61,
ECONNRESET: 54,
EDEADLK: 11,
EDESTADDRREQ: 39,
EDOM: 33,
EDQUOT: 69,
EEXIST: 17,
EFAULT: 14,
EFBIG: 27,
EHOSTUNREACH: 65,
EIDRM: 90,
EILSEQ: 92,
EINPROGRESS: 36,
EINTR: 4,
EINVAL: 22,
EIO: 5,
EISCONN: 56,
EISDIR: 21,
ELOOP: 62,
EMFILE: 24,
EMLINK: 31,
EMSGSIZE: 40,
EMULTIHOP: 95,
ENAMETOOLONG: 63,
ENETDOWN: 50,
ENETRESET: 52,
ENETUNREACH: 51,
ENFILE: 23,
ENOBUFS: 55,
ENODATA: 96,
ENODEV: 19,
ENOENT: 2,
ENOEXEC: 8,
ENOLCK: 77,
ENOLINK: 97,
ENOMEM: 12,
ENOMSG: 91,
ENOPROTOOPT: 42,
ENOSPC: 28,
ENOSR: 98,
ENOSTR: 99,
ENOSYS: 78,
ENOTCONN: 57,
ENOTDIR: 20,
ENOTEMPTY: 66,
ENOTSOCK: 38,
ENOTSUP: 45,
ENOTTY: 25,
ENXIO: 6,
EOPNOTSUPP: 102,
EOVERFLOW: 84,
EPERM: 1,
EPIPE: 32,
EPROTO: 100,
EPROTONOSUPPORT: 43,
EPROTOTYPE: 41,
ERANGE: 34,
EROFS: 30,
ESPIPE: 29,
ESRCH: 3,
ESTALE: 70,
ETIME: 101,
ETIMEDOUT: 60,
ETXTBSY: 26,
EWOULDBLOCK: 35,
EXDEV: 18
},
signals: [Object: null prototype] {
SIGHUP: 1,
SIGINT: 2,
SIGQUIT: 3,
SIGILL: 4,
SIGTRAP: 5,
SIGABRT: 6,
SIGIOT: 6,
SIGBUS: 10,
SIGFPE: 8,
SIGKILL: 9,
SIGUSR1: 30,
SIGSEGV: 11,
SIGUSR2: 31,
SIGPIPE: 13,
SIGALRM: 14,
SIGTERM: 15,
SIGCHLD: 20,
SIGCONT: 19,
SIGSTOP: 17,
SIGTSTP: 18,
SIGTTIN: 21,
SIGTTOU: 22,
SIGURG: 16,
SIGXCPU: 24,
SIGXFSZ: 25,
SIGVTALRM: 26,
SIGPROF: 27,
SIGWINCH: 28,
SIGIO: 23,
SIGINFO: 29,
SIGSYS: 12
},
priority: [Object: null prototype] {
PRIORITY_LOW: 19,
PRIORITY_BELOW_NORMAL: 10,
PRIORITY_NORMAL: 0,
PRIORITY_ABOVE_NORMAL: -7,
PRIORITY_HIGH: -14,
PRIORITY_HIGHEST: -20
}
},
EOL: '\n',
devNull: '/dev/null'
}
무슨 소리야..
잘은 모르겠지만 노트북의 운영체제 정보가 나온 것 같다.
이와 같이 node에는 내장모듈이 있으며 이를 효율적으로 사용하는 것이 중요하다.
서버 또한 이 내장모듈로 열고 관리한다.
global.console.log();
global.console.time(); //코드 시작 시간 매개변수로 해당 테스트 이름을 문자열 작성
global.console.timeEnd(); //코드 종료후 시간 출력
// 전달된 객체를 표형태로 보여주는 메소드
// global.console.table({a: { name: "이무헌" },b: { name: "이무헌2" },c: { name: "이무헌3" },});
// 실행시키면 실행한 파일의 이름까지 보여줌
console.log(__filename);
// 실행한 파일의 directory까지 보여줌
console.log(__dirname);
// 나중에 필요할 때가 생기니 잘 알아둘것~
a서버에서 코드를 작성할 때 클라이언트에게 데이터가 몇 초후의 전달되며 얼마나 빨리 처리되는지 알기 위해선 위와같은 time메소드가 매우 필요하다.
실행파일 및 directory까지 편리하게 확인 가능하다.
이제 vsc에서 우클릭+상대경로 안해도 된다….
// process 객체
process.env
// console.log(process.env);
console.log(process.version) //노드의 설치 버전
console.log(process.execPath); //노드의 경로
console.log(process.cpuUsage()); //cpu 사용량
process라는 객체는 환경변수 env를 가진다. 그 외에도 다양한 객체를 가진다.
process.argv
: 이 속성에는 Node.js 프로세스에 전달되는 명령줄 인수 배열이 포함되어 있습니다. 배열의 첫 번째 요소는 Node.js 실행 파일의 경로이고 두 번째 요소는 실행 중인 스크립트의 경로입니다. 나머지 요소는 스크립트에 전달된 명령줄 인수입니다.process.env
: 이 속성에는 Node.js 프로세스에서 사용할 수 있는 환경 변수를 나타내는 개체가 포함되어 있습니다. process.env.SOME_VARIABLE
과 같이 변수 이름을 키로 사용하여 특정 환경 변수에 액세스할 수 있습니다.process.exit([code])
: 이 메서드는 지정된 종료 코드로 Node.js 프로세스를 종료합니다. 코드가 제공되지 않으면 프로세스는 코드 0(성공)으로 종료됩니다.process.on(event, listener)
: 이 메서드를 사용하면 프로세스 수준 이벤트에 대한 수신기를 등록할 수 있습니다. 수신 대기할 수 있는 일부 이벤트에는 프로세스가 종료하려고 할 때 발생하는 exit
와 처리되지 않은 예외가 발생할 때 발생하는 uncaughtException
이 포함됩니다.process.cwd()
: 이 메서드는 Node.js 프로세스의 현재 작업 디렉터리를 반환합니다.process.pid
: 이 속성에는 Node.js 프로세스의 프로세스 ID가 포함됩니다.process.platform
: 이 속성에는 win32
, darwin
또는 linux
와 같이 Node.js 프로세스가 실행 중인 운영 체제 플랫폼을 나타내는 문자열이 포함됩니다.// 우리가 window를 생략해서 작성하던 것과 같이
// window.console.log()
// console.log()
// global과 module을 생략해서 작성할 수 있다.
// console.log(module.exports===exports);
// true 생략을 해도 된다.
a 우리가 일반 js에서 console.log에서 window를 생략했던 것 처럼 node도 생략이 가능하다.
바닐라 js에선 this가 window를 가리키지만 node에선 this가 global을 가리킨다.
하지만 역시 global을 생략이 가능하다.
이처럼 우리는 module을 생략 할 수도 있다!
exports.objs = { a: 1 };
exports.add = () => {
return 2;
};
a이렇게 하면 exports에서 objs와 add함수를 내보내게 된다.
이제 받아보자
const BlockClass = require("./index5");
// const require=(path)=>{
// // 1.해당 파일의 (path)를 가져오고
// // 2.해당 소스코드를 실행시킨다.
// // 3. return module.exports
// }
// ES 6
// nodejs가 자체적으로 모듈의 문법을 만든 것
// 모듈 시스템을 구축한 것.
console.log(BlockClass);//{ objs: { a: 1 }, add: [Function (anonymous)] }
a 정상적으로 출력이 됨을 알 수 있다. 그렇다면 module.exports로는 어떻게 내보낼까? 즉,변수를 객체에 담아 보내려면?
const objs = { a: 1 };
const add = () => {
return 2;
};
const objss = {
objs: objs,
add: add,
};
// exports.objs = { a: 1 };
// exports.add = () => {
// return 2;
// };
module.exports=objss
객체와 함수를 하나의 object에 담아 보냈다.
const BlockClass = require("./index5");
// const require=(path)=>{
// // 1.해당 파일의 (path)를 가져오고
// // 2.해당 소스코드를 실행시킨다.
// // 3. return module.exports
// }
// ES 6
// nodejs가 자체적으로 모듈의 문법을 만든 것
// 모듈 시스템을 구축한 것.
console.log(BlockClass); //{ objs: { a: 1 }, add: [Function: add] }
똑같이 나온다. 그렇다면 구조분해할당을 이용해보자
const objs = { a: 1 };
const add = () => {
return 2;
};
// exports.objs = { a: 1 };
// exports.add = () => {
// return 2;
// };
module.exports={objs: objs,
add: add}
똑같이 나온다. 받는쪽에서 마찬가지로 구조분해로 받을 수 있다.
const {objs,add} = require("./index5");
// const require=(path)=>{
// // 1.해당 파일의 (path)를 가져오고
// // 2.해당 소스코드를 실행시킨다.
// // 3. return module.exports
// }
// ES 6
// nodejs가 자체적으로 모듈의 문법을 만든 것
// 모듈 시스템을 구축한 것.
console.log(objs,add); //{ a: 1 } [Function: add]
개인적으로 구조분해 할당으로 가져오는 방법이 더 깔끔하고 좋은 것 같다.
변수를 외우지 않아도 되고
// 웹서버 ㄱ
// 내장모듈 가져오자
const http = require("http");
// createServer 메소드는 서버 객체를 만들어 주고
// 클라이언트의 요청을 받으면 호출이 된다.
// 전달된 콜백 함수는 클라이언트의 요청을 받아서 처리 후
// 클라이언트에 응답해준다.
const server = http.createServer((req, res) => {
// res.setHeader("Content-Type", "text/plain; charset=utf-8");
res.end("serverOn");
})
node 내장함수를 이용하여 서버를 만들었다.
// 포트
// 3000번 포트 같은... 포트를 지정하는 이유
// 네트워크 프로세스를 나눠 주기 위해서
// http 80 https 433
// 시스템 예약 포트이외의
// 사용하지 않을 것 같은 포트들을 사용하면 된다.
// 1025~65535까지 안에서
// 거의 많이 사용되는건 8000,8080
const PORT = 4000;
// 서버 객체의 listen 메소드를 호출해서
// 클라이언트의 요청을 대기상태로 만들어 줄 수 있다.
// 이벤트 루프를 돌면서 요청이 오기까지 대기를 하다가
// 요청이 오면 응답해준다.
// listen매개 변수로 첫번째로 port
server.listen(PORT, () => {
console.log(+PORT + "=> 이녀석..성공했구나");
});
그 후, 포트를 설정하여 서버 생성 이벤트를 만들어 주면 된다. 요청이 온다면 listen이 응답해준다. 응답이 성공적으로 끝난다면 res로 end에 정의한 매개변수를 전달한다!