구글 크롬의 자바스크립트 엔진에 기반해 만들어진 자바스크립트 런타임
런타임이란 ? "프로그래밍 언어가 구동되는 환경" 을 말한다.
Node.js는 1.간단한 로직 2.대량의 클라이언트가 접속하는 서비스(=입출력이 많은 서비스) 3.빠른 개발 요구 4. 빠른 응답시간 요구 5. 비동기식에 어울리는 서비스 (ex.스트리밍/채팅)
js의 런타임 환경은 웹 브라우저만 존재했기 때문에
서버를 단 언어로 사용하기 위해 나온것이 node.js 이다. 그러므로 웹 브라우저 없이 실행이 가능!
+참고하기
https://nodejs.org/en 에 들어가서 다운로드 받은 후 install 설치하면 된다.
터미널 또는 명령 프롬프트를 열어
node -v
npm -v
를 치면 현재 내가 설치한 버전을 확인할 수 있다.
Node Package Manager
https://www.npmjs.com/
노드 패키지를 관리해주는 도구. 노드를 설치하면 함께 제공되고, 자바스크립트로 개발된 각종 모듈의 설치, 업데이트, 구성, 제거 과정을 자동화하여 관리해주는 기능이다.
❓ 패키지란?
npm에 업로드된 노드 모듈. 패키지들 간 의존관계가 존재한다.
❓모듈이란?
모든 코드를 짜지 않고 쇼핑몰에서 쇼핑하듯이 재료를 담는것이라고 생각하자. 모듈이 있으면 별도로 코드를 짜지 않아도 모듈을 다운받아 쓸수 있는 "기능 단위" 이다
터미널에 npm install 모듈이름 을 치면 알아서 다운,설치됨
ex. npm install express
두 파일은 프로젝트의 종속성(dependency) 와 버전 관리를 도와주는 역할을 한다.
package.json
package-lock.json
npm init
: 프로젝트를 시작할 떄 사용함
npm init --yes
: package.json이 생성될 때 기본값으로 생성한다. 위에 꺼 일일히 치기 귀찮을때 쓰면됨
napm install 패키지 이름(=모듈이름)
: 프로젝트에서 사용할 패키지를 설치함. 설치된 패키지의 이름과 정보는 package.json의 dependencies 에 입력된다.
** 위와 같이 치면 해당 프로젝트에만 적용되지만 install 뒤에 -g를 붙이면 전역에 패키지를 설치한다.
R(Read) → E(Evaluate) → P(Print) → L(Loop)
: 읽기 → 평가 → 출력 → 반복
윈도우에서의 cmd, 맥에서의 terminal ( vscode의 터미널이랑 다름 ) 처럼
노드에는 REPL콘솔이 있다.
사용자가 명령을 입력하면 시스템이 그 명령을 읽고 평가하며 결과를 출력하고, 이 프로세스가 반복되는 환경을 말한다.
REPL은 특히 인터프리터 언어에서 많이 사용된다.
Python, JavaScript, Ruby, 등의 언어에서는 REPL을 통해 코드를 즉시 실행하고 결과를 확인가능하며 이는 코드를 작성하면서 즉각적인 피드백을 받을 수 있어 개발 및 실험에 유용하다.
- 자바스크립트 언어 사용
- Single Thread
- Non-blocking I/O
- 비동기적 Event-Drive
: 한 번에 하나의 작업만 처리하는 프로그램이나 프로세스를 가리키는 용어
노드는 싱글 스레드라 주어진 일을 하나밖에 처리못한다.
=> I/O가 많이 발생하는 웹 서버나 네트워크 서비스 등에서 높은 성능을 발휘할 수 있음 //
프로세스와 스레드로 나뉘는데 프로세스 안에 스레드가 있음.
프로세스
Thread(스레드)
Node.js는 기본적으로 하나의 메인 스레드만 사용한다 이 스레드는 이벤트 루프를 실행하고 비동기 I/O 작업을 처리함.
- 에러를 처리하지 못하는 경우 멈춘다. 예외처리가 중요함!
- 프로그래밍 난이도가 쉽고, cpu, 메모리 자원을
적게 사용한다.
: Non-blocking I/O 기능으로 비동기 I/O 작업을 통해 오래걸리는 작업, 그러니까 다수의 동시 요청을 효율적으로 처리 할 수 있다.
차례를 기다림. 이전 작업이 끝나야만 다음 적업 수행.
데이터의 요청과 결과가 한 자리에서 동시에! 일어남
시간이 얼마 걸리든지 요청한 자리에서 결과가 주어져서
한 요청에 서버의 응답이 이루어질 때까지 계속 대기해야함.
차례를 기다리지 x. 요청이 완료된 순서대로 처리
동시에 일어나지 않으며 요청한 후 응답을 기다리지 않고 다른 활동을 한다.
I/O는 input/output의 약자로 컴퓨터 시스템에서 데이터를 입력받거나 출력하는 모든 작업을 나타냄.
이벤트가 발생할 때 미리 지정해둔 작업을 수행한다는 뜻
예를 들면 클릭, 네트워크 요청, 타이머 등 이 있고
이벤트가 발생할 때마다 콜백 함수를 실행하여 작업을 처리하는 방식이다. 이를 통해 비동기 프로그래밍이 간편해지고, 성능 향상이 이루어짐.
이벤트 루프(event loop)는 여러 이벤트가 동시에 발생했을 때 어떤 순서로 콜백함수를 호출 할지를 이벤트 루프가 판단한다.
노드는 이벤트가 종료될 때까지 이벤트 처리를 위한 작업을 반복하므로 루프(loog)라고 부른다.
ex) 파일시스템에서 데이터를 읽는 I/O작업이 완료되면 이를 처리하기 위한 이벤트가 이벤트 루프에 등록되고 해당 이벤트가 발생하면 콜백함수가 실행됨!
LIFO : 마지막에 나간게 가장 먼저 나온다
특정한 기능을 하는 함수나 변수들의 집합.
재사용 가능한 코드조각
package.json 에 “type”: “module” 을 추가해 사용
하나의 모듈 파일에 하나 만들기
function connect(){ return a+b; } module.exports = connect;
하나의 모듈 파일에 여러개 만들기
const add = (a,b) => a+b; const PI = 3.141592; const E = 2.718; //방법1. 객체로 감싸서 보내기 module.exports = { add: add, PI: PI // 걍 PI만 써도됨 E: E } //방법2. 하나씩 내보내기 module.exports.add = add; module.exports.PI = PI; module.exports.E = E; //방법2의 생략 exports.add = add; exports.PI = PI; exports.E = E;
math모듈을 불러와서 사용할거에요
const add = require('./math');//require 사용해서 파일불러오기 require:요구하다 console.log(add(5, 7)); //12
import써서 불러올거에요
import {add} from "./math.js"; console.log(add(5,6)); //11
여러개 내보냈을때 불러오는거는요
const math2 = require('./math2'); console.log(math2.add(3,4)); //math2에 add console.log(math2.E); //math2에 E
구조분해한 애들은 이렇게 불러와요
const {add, PI, E} = require('./math2') console.log(PI);
node를 통해 서버를 구축하는 방법은 1.http와 2.express가 있다
응답 메시지를 작성할 때 첫 번째 매개변수로 전달되는 객체
응답 메시지를 작성할 때 두 번째 매개변수로 전달되는 객체
response 객체로
writeHead : 응답 헤더 작성
write : 응답 본문 작성
end : 응답 본문 작성 후 응답 종료 로 구성된다. end를 안써주면 계속 돈다.
// http 모듈로 웹서버생성하기 const http = require('http'); const fs = require('fs'); const server = http.createServer(function (req,res){ //response객체를 썼으니 응답head,본문,end를 지정 res.writeHead(200, {'content-type':'text/html,charset-utf8'}) //응답헤더 res.write('<h1>Hello, Node.js! </h1>'); // 응답 본문 res.end('<p> My First node server! </p>'); // 응답 종료 })
try {
const data = fs.readFileSync('./inde.html');
res.writeHead((200, { 'content-type': 'text/html, charset-utf8' }));
res.write(data);
res.end();
} catch (error) {
console.log(error);
const PORT = 8000;
// request 이벤트 : 클라이언트 요청
server.on('request', function (req, res) {
console.log('request 이벤트 발생!', req.url)
})
// connection 이벤트 : 클라이언트가 접속(클라이언트-서버 연결됐을때)했을 때 발생
server.on('connection', function (req, res) {
console.log('connection 이벤트 발생!')
})
server.listen(PORT, function () {
console.log(`server listening on ${PORT}`)
})
웹서버를 생성하는 것과 관련된 기능을 담당하는 프레임워크
웹 애플리케이션을 만들기 위한 각종 메소드와 미들웨어 등이 내장되어 있음
http 이용시에는 코드의 가독성와 확장성이 낮음
이를 해결하기 위해 만들어진것이 express 프레임워크
터미널에 npm install express
입력하면
npm_modules 가 만들어지며 express에 관련된 폴더가 생성된다. 해당 package.json의 dependencies 에 express 기록한다
** 설치하면 너무많은 폴더들이 저장되기때문에 이대로 깃허브에 push하면 불필요함. 그러니 .gitignore 써서 제외하고 push하자!
express모듈이 export, 그러니까 모듈내보내기하는 최상위 함수로 express application을 만듦.
Express() 함수를 호출함으로써 만들어진 express application
ejs는 자바스크립트 코드를 HTML파일 안에서 사용가능하게 만들어주는 모듈. 동적 웹 페이지를 생성하는 템플릿 엔진 중 하나이다. (확장자는 .ejs)
템플릿 엔진 : 문법과 설정에 따라 파일을 html형식으로 변환시키는 모듈을 말한다
$ npm install ejs
<%%> 무조건 자바스크립트 코드가 들어가야하고, 줄바꿈할 경우 새로운 <%%>를 이용해야한다
<% = %> : js코드 실행한결과를 템플릿에 출력할때 사용한다
<%- include ('view의 상대주소')%> 다른 view파일을 불러올때 사용한다
<%- include('./component/header')%>
<h1>Hello EJS</h1>
<% for (let i =0; i <5; i++) { %>
<div>hi~ <%= i %>번째</div>
<%= i %> //변수값을 출력하는 부분
<% } %>
: Express.js와 같은 웹 프레임워크에서 HTTP 요청과 응답 사이에 위치하여 요청 또는 응답의 기능을 확장하거나 수정하는 함수
요청이 들어옴에 따라 응답까지의 중간 과정을 함수로 분리한것
서버와 클라이언트를 이어주는 중간작업
이미지, css 파일 및 Javascript 파일(front)과 같은 정적 파일 제공 => 정적 파일은 서버에 요청이 올 때마다 변경되지 않고 고정된 파일로 존재하며, 클라이언트에게 직접 제공
Express 에 있는 static 메소드를 이용해 미들웨어로 로드
앞 쪽'/static'은 클라이언트파일을 의미하고 뒤에는 실제파일을 의미
listen(port, )
port? 선착장의 개념이라고 생각하자. (ex.IP는 대표전화/ PORT는 ars내선번호) 주소가 아니고 포트가 따로 있음. 그러니 listen을 하고 있어야 수행이 가능하겠죠?
한 서버 내에 여러개 사용이 가능하며 포트마다 다른 기능을 수행함!
localhost? 내 컴퓨터의 IP를 굳이 안써도 됨. 내 컴터로 접속할때만 사용가능
app.get ('/' , () => {})
여기서 get은 http의 메소드 . '/'은 라우팅 . ()=>{}는 콜백함수이다.
http 메소드 : 요청의 목적, 종류를 알리는 수단
요청방식에는 get 방식과 : 주소창에서 데이터 전달
post 방식이 있다. : 내부적으로 body에 데이터 전달
라우팅 : 특정 포트 안에서도 여러 파일이 있는데 / 또는 /about 뭐 이런 주소창에 보면 /슬래쉬 뒤에 써있는 것들을 라우팅이라한다.
콜백함수 : 함수(끝나고 실행할 함수)
이다
ex. setTimeout(() => {},1000) : 1000ms 1초뒤에 콜백함수를 실행해라
ex2. app.get ('/', (req,res){
res.send('hello');
}) : 해석) app이 로컬host로 들어온 express앱. 이 express 앱에 라우팅이 루트(젤 기본주소)로 들어왔을때, 그때 콜백함수를 실행하겠따
여기서 req : 요청에 대한 정보가 담겨있음
res란 : 응답에 대한 정보가 담겨있음 so, 서버란 요청과 응답의 연속!
키값과 변수명이 일치해야함.
const obj = {
title: '독전2',
star: 1,
content: '제발 보지마라..'
}
// 만약 구조분해를 안했다면
console.log(obj.content, obj.star, obj.title);
// -> 구조분해
// key가 존재하지 않는 경우 대비하여 default 값 할당
const { content, star, title, price = 1000} = obj;
const arr = ['first', 'second'];
const [one, two] = arr ; //배열은 인덱스로 넣어준다
console.log (one); // first 나옴
//undefined
const arr2 = ['a','b','c'];
const [x,y,z,alpha] = arr2;
console.log(x,y,z,alpha); // a b x undefined
//undefined에 기본값 지정해주기
const list = ['apple', 'orange'];
const [f1, f2, f3 = 'banana'] = list; //f3이 undefined가 뜰거기때문에 banana라는 기본값 지정해줌
let x =1 , y = 3;
[x,y] = [y,x];
console.log(x,y); //3,1
▫ A && B : 두 개의 피연산자 모두 true여야 true를 반환
▫ A || B : 두 개의 피연산자 중 하나만 true여도 true를 반환
console.log(true && true); // true를 반환하겟쬬?
console.log(false && true); // false
console.log(true || false); // true
console.log(false || true); // true
예를 들어 이럴 때 쓴다
&& (논리곱)
const v1 = 5;
const v2 = 7;
const result2 = v1 > v2 && 'v1이 큼';
console.log(result2); //false 뜸
const result3 = v1 < v2 && 'v2가 큼';
console.log(result3); //v2가 큼
|| (논리합)
const result4 = v1 || 100; // 앞에 값이 true기 때문에 뒤에까지 검사x
console.log(result4); // 5
const nameEx = '홍길동' ;
const nameEx2 = null;
console.log(nameEx || '이름x'); //홍길동
console.log(nameEx2 || '이름x'); // 이름x //첫째값이 null이기 때문에 뒤에까지 가서 이름x가 출력됨
spread : 호출시 함수의 파라미터에 사용
rest : 호출받는 함수의 파라미터에 사용(=선연부분)
: 반복 가능한 객체에 사용하는 문법이다.
객체의 요소에 접근해서 요소들을 하나씩 분리 후 전개요소에 접근해서 반환ㅇ한다.
배열, 유사 배열, 문자열 등에 사용 가능하고
...
연산자를 사용한다.
const arr1 = [1,2,3];
const arr2 = [4,5,6];
// 두 배열을 합치려면 합칠 변수 선언해주고 ...
const arr3 = [...arr1, ...arr2];
const str = 'hello';
console.log([...str]); //h,e,l,l,o 문자열이 분해가됨
console.log([...'hello']); //동일한 의미
console.log(str.split('')); //동일한 의미
const chip = {
base: 'chip',
company: 'lotte'
}
const potatiChip = { //기존의 객체값을 이용해서 새로운 객체값을 만들고 싶을 때 사용하면 좋겟쥬?
...chip,
flavor: 'onion'
}
console.log('chip: ',chip);
console.log('potatochip: ',potatiChip);
const values = [1, 2, 3, 4, 5];
// 함수 선언 (rest 사용)
function get(a,b, ...rest){
console.log('a : ', a); // 1
console.log('b : ', b); // 2
console.log('rest : ', rest); // [3,4,5]
// 함수 호출 (spread 사용)
get(...values);
get(values);
/* get(values)를 실행하면 이렇게 나오니 주의
a : [ 1, 2, 3, 4, 5 ]
b : undefined
rest : []
*/
const icecream = {
flavor : "choco",
price: 1000,
company: 'binggre'
}
const {flavor, ...rest} = icecream;
console.log(flavor); //choco
console.log(rest); //{ price: 1000, company: 'binggre' }
const number = [1,2,3,4,5,6];
const [one, two, ...num] = number;
//rest의 이름은 내맘대로 설정해도됨 !
//why? 앞에 ...spread가 있으니까 rest라 안적어도 나머지 나옴
console.log(one); // 1
console.log(two); // 2
console.log(num); // [ 3, 4, 5, 6 ]
...은 []괄호를 씌워주는거니까
const [...num1] = number;
console.log(num1); // [ 1, 2, 3, 4, 5, 6 ] 이렇게 나오겠쬬?
: 객체 생성 템플릿
즉, 오브젝트(=객체)를 만들 수 있는 "틀"(=템플릿)
정해진 틀로 같은 규격의 오브젝트를 여러개 만들수잇음 like 붕어빵틀..
재사용할 때 유리하겟쥬?
: 클래스 생성 시 이름은 PascalCase로 쓴다!!
: new 키워드를 이용해서 미리만들어둔 클래스 형태의 오브젝트를 만들수 있음 => instance화 라고 한다.
//클래서 정의
class House {
//constructor 이용하여생성자 함수 만들기=>클래스객체를 생성할때마다 속성 초기화 해줌
constructor(year, name){
//전달받을 속성들 작성
this.year = year;
this.name = name;
}
//메소드
getAge(){
console.log(`${this.name}는 건축한지 ${2023-this.year}년 했다!`);
}
}
// 클래스 이용해서 객체 만들기
const house1 = new House(2010,'아파트');
console.log('house1 : ', house1);
console.log(house1.name); //아파트
house1.getAge();//아파트는 건축한지 12년 됐다.
extends라는 키워드를 사용해 상속받을 수 있다.
그러면 기존에 있던 클래스의 속성과 메소드 + 추가적인 속성과 메소드를 정의할 수 있음
class Apartment extends House {
constructor(year, name, window, floor){
// super라는 키워드를 통해 부모 객체에서 상속 받음 => 상속 받은 부모 클래스의 생성자를 호출
super(year, name, window);
this.floor = floor; //애는 Apartment에서 추가로 만든거니까 따로 지정해줘야함
}
getFloor(){
return `${this.year}년에 지어진 ${this.name}의 층수는 ${this.floor}이다`;
}
// 오버라이딩
// 부모 클래스에 정의되어 있는 메소드를 이름은 동일하게 쓰되, 내용은 다르게
getAge(){ //여기서 다시 정의하겠다~
console.log(`${2023-this.year}년 된 ${this.name}는 총 ${this.floor}층이다.`)
}
}
const apt1 = new Apartment(2022, '레미안' , 100, 500);
console.log(apt1);
apt1.getAge();
console.log(apt1.getFloor()); //getAge나 getWindow도 동일하게 쓸수있다
공통점 :
프로그램이나 시스템에서 작업들이 어떻게 실행되는지에 대한 개념
: 순차적으로 실행된다. 한 작업이 끝나야 다음 작업이 시작. 코드가 위에서 아래로 순차적으로 실행되기 때문에
=> 성능이 저하될 수 있음.
: 순차적이지 x . 작업완료를 기다리지 않고 빨리끝나는거부터 실행
=> 주로 네트워크 요청, 파일 읽기/쓰기, 데이터베이스 쿼리 등 시간이 오래 걸리는 작업에 유용
console.log("첫 번째 작업");
setTimeout(() => {
console.log("두 번째 작업 (비동기)");
}, 1000);
console.log("세 번째 작업");
순서대로 안나오는 모습 확인
콜백함수는 다른 함수에 인수(=매개변수)로 전달되서, 특정 이벤트가 발생하거나 특정 조건이 충족될 때 ! 실행함.
비동기 방식으로 작성된 함수를 동기처리하기 위하여 사용함
: 비동기 함수를 동기처리 하기 위해 만들어짐
promise의 상태에는
pending(대기) : promise를 수행 중인 상태
fulfilled(이행) : promise가 resolve된 상태 =성공
rejectd(거부) : promise가 지켜지지 못한(reject된) 상태 = 실패
settled : 이행 또는 거부로 결론이 난 상태
//우린 아직 서버와 연결이 안되기 때문에 promise객체를 반환하는 promise1함수를 정의해줄것임.
예를 들어
function promise1(flag){
return new Promise(function(resolve,reject){
})
}
promise는 두가지 콜백함수를 가지는데
promise보다 직관적인 코드를 위해 등장함
기능이 추가된게 아니라 promise를 다르게 사용하는것!
<출처 및 레퍼런스>
포스코X코딩온
TCP school https://www.tcpschool.com/javascript/intro
ChatGPT