chapter1. node.js 개요
[Contents]
1. node.js의 특징을 이해하고 설명할 수 있다
2. node.js 프로젝트를 생성할 수 있다
[About Node.js]
chrome v8 javascropt 엔진으로 빌드된 javascript 런타임(확장성 있는 네트워크 애플리케이션 개발에 사용되는 소프트웨어 플랫폼)
[node.js 등장 이전과 이후]
node.js 등장 이전?
- 특정 웹 브라우저(chrome, firefox,safari,exploer)안에서 동작
- 독립적으로는 사용될 수 없었음
- 웹에서 표시되는 client만 구현 가능
node.js 등장 이후?
- javascript 런타임 환경이 만들어져 웹 브라우저에서 독립되어 터미널 등에서 Javascript 실행 가능
- 웹 브라우저와 무관한 독립적인 프로제그램 만들 수 있음
- Server 부분에서도 javascript 사용가능
[node.js 특징]
javascript : 새로운 언어를 습득하지 않고도 javascript를 활용해 서버 기술을 향상시킬 수 있음
chrome v8 자바스크립트 엔진: 다른 javascript 엔진과는 비교할 수 없을 만큼 빠르며 오픈소스 코드로 공개되어 있음
npm(node packahe manager)을 통한 다양한 모듈(패키지)제공: npm을 이용해 필요한 라이브러리와 패키지를 검색해서 설치하고 사용가능
< 단일 쓰레드의 non-blocking I/O 이벤트 루프 기반 비동기 방식 >
단일 쓰레드 (Single Thread)?
- 하나의 프로세스에서 하나의 쓰레드를 실행하므로, 프로세스 내의 작업을 순차적으로 실행
- 유저와 상호작용하는 어플리케이션의 경우, 한 가지 작업이 끝난 뒤에야 다음 작업으로 이동하기 때문에 유저가 원하는 작업 수행이 빠르게 이루어지지 않을 수 있음
동기(Sync) / 비동기(Async): 처리해야 할 작업들에 대한 처리 과정
동기(Synchronous): 호출된 작업의 리턴하는 시간과 결과를 반환하는 시간이 일치하는 경우
비동기(Asynchrous): 호출된 작업의 리턴하는 시간과 결과를 반환하는 시간이 일치하지 않는 경우
블로킹(Blocking)/ 논블로킹(Non-Blocking):
직접 제어할 수 없는 대상을 처리하는 방법으로 이전작업이 완료될 때 까지 기다리지 않고 다음 작업이 진행되거나/되지 않도록 동작하는 패러다임
Blocking: 직접 제어할 수 없는 작업이 끝날 때까지 기다려야 하는 경우 호출된 함수에서 I/O 작업등을 요청했을 경우 I/O 작업이 처리되기 전까지 아무일도 하지 못함
Non-Blocking: 직접 제어할 수 없는 작업이 완료되기 전에 제어권을 넘겨주는 경우 호출된 함수에서 I/O 작업 등을 요청했을 경우 I/O 작업의 처리 여부와 관계없이 바로 다음 작업을 할 수 있음
동기-블로킹: 요청의 실행시간과 종료시간이 보장되며 내부의 I/O 작업 또한 종료 까지 대기 후 작업이 반환
동기-논블로킹 : 요청의 실행시간과 종료 시간이 보장되지만 작업의 반환여부와 상관없이 부가적인 작업이 이루어짐
비동기- 논블로킹: 각 작업이 순차적인 실행순서를 보장하지 않으며 요청과 작업이 호출되면 다른 작업을 받을 대기를 함
비동기- 블로킹: 비효율적이라 사용되는 모델이 많지 않음 but, Node.js+MySQL을 사용하는 경우 MySQL 드라이버가 Blocking 방식으로 동작하기 때문에 논블로킹 방식일지라도 블로팅 되는 경우가 발생할 수 있음
이벤트 루프(Event Loop)?
- 여러 이벤트가 동시에 발생했을 때 어떤 순서로 Callback 함수를 호출할 지 판단
Call Stack : 현재 실행중인 서브루틴에 관한 정보를 저장하는 스택 자료 구조 ->firstin lastout
TaskQueue: 이벤트 발생 후 타이머나 이벤트 리스너의 콜백들이 줄 서 있는 곳
이벤트 루프(Event Loop)?
- Call Stack에 현재 실행중인 실행 컨텍스트가 있는지, 이벤트 Queue에 대기 중인 함수가 있는지 반복해서 확인
- Call Stack이 비어있고 이벤트 Queue에 대기중인 함수가 있다면 순차적으로 Queue의 FIFO(First In First Out)특징에 따라 대기중인 함수를 Call Stack으로 이동시켜 함수가 실행되게 함
[node.js단점]
1. 이벤트 기반 비동기 방식으로 서버단 로직이 복잡한 경우 콜백함수의 늪에 빠질 수 있음 (ex. 요청에 의해 조회한 결과값에 따라 다른 로직을 처리해야 하는 경우)
2. 코드를 순차적으로 실행하는 것이 아니라 비동기 방식으로 이벤트를 보내므로 자바 개발 방식으로 설계하고 프로그래밍하면 큰 문제가 발생할 수 있음
3. 단일 쓰레드 이기 때문에 하나의 작업 자체가 많이 걸리는 웹서비스에는 어울리지 않음
4. 코드가 수행되어야 코드에 에러가 있는지 알 수 있음
5. 반드시 모든 케이스에 대해 소스코드를 검증해야 함
[node.js가 어울리는 웹서비스?]
1. 간단한 로직
2. 대용량(동시에 여러 request 처리)
3. 빠른 응답시간 요구
4. 빠른 개발 요구
5. 비동기 방식에 어울리는 서비스(네트웨크 스트리밍 서비스, 채팅 서비스 등)
ex) NETFLIX, Uber, PayPal
[node.js가 어울리지 않는 웹서비스?]
1. 단일 처리가 오래 걸리는 경우(싱글 쓰레드 이기 때문)
2. 서버 체크 로직이 많은 경우(call back hell)
3. 업무 복잡도/난이도가 높은 경우(에러가 나면 서버가 죽음)
[node.js를 사용하면 좋은 경우]
1. 간단한 요구사항이 많은 경우
ex. 채팅, CRUD 기반 서비스
기업: NETFLIX, Uber, PayPal, slack
[스프링을 사용하면 좋은 경우]
복잡한 요구사항이 많은 경우
ex. 실시간 게임, 영상처리
기업: trivago, udemy, CRED
[ch2.node.js 모듈과 객체]
- 모듈과 모듈시스템
모듈이란? 특정한 기능을 하는 함수나 변수들의 집합
모듈시스템이란? 모듈로 분리된 javascript 파일들을 불러오는 방식을 정의 한 것
[Ex01FirstServer.js]
const http = require('http');
http.createServer((req,res)=>{
}).listen(8888, ()=>{
console.log('8888 포트에서 서버 연결중.....')
});
[Ex02ModuleNObject]
[func.js]
const {odd,even} = require('./var');
function checkOddOrEven(num){
if(num%2){
return odd;
}else{
return even;
}
}
module.exports = checkOddOrEven;
[var.js]
const odd = '홀수입니다';
const even = '짝수입니다';
module.exports={
odd,
even,
};
//위에 아님 아래로 작성
exports.odd = '홀수입니다';
exports.even = '짝수입니다';
[index.js]
const {odd,even} = require('./var');
const checkOddEven = require('./func');
function checkStringOddEven(str){
if(str.length %2){
return odd;
}else{
return even;
}
}
module.exports =checkStringOddEven;
console.log(checkOddEven(3));
console.log(checkStringOddEven('helloworld'));
[Ex02console.js]
//특정 레이블에 해당하는 time~timeEnd 사이의 시간 측정
console.time('전체 시간');
console.log('일반 로그');
console.error('에러 메세지');
console.table([{name:'예진', age:25},{name:'자연', age:20}]);
const obj ={
outside : {
inside:{
key: 'value',
}
}
}
console.dir(obj, {colors : false, depth : 2}); //depth 기본값 2
console.dir(obj, {colors : true, depth :1});
console.timeEnd('전체 시간');
[Ex03Timer.js]
//setTimeout: n초후 실행
const timeout = setTimeout(()=>{
console.log('1.5초 후 실행');
}, 1500);
//setInterval : n초마다 실행
const interval = setInterval(()=>{
console.log('1초마다 실행');
}, 1000);
const timeout2 = setTimeout(()=>{
console.log('실행되지 않습니다');
},3000);
setTimeout(()=>{
clearTimeout(timeout2); //생성한 timeout 삭제
clearInterval(interval); //생성한 interval 삭제
}, 2500);
const immediate = setImmediate(()=>{
console.log('즉시 실행');
});
clearImmediate(immediate); //생성한 immediate 삭제
[Ex04js1]
const js2 = require('./Ex04js2');
console.log('js2 : ', js2);
module.exports = () => {
console.log('js2', js2);
}
[Ex04js2]
const js1 = require('./Ex04js1');
console.log('js1 : ', js1);
module.exports = () => {
console.log('js1', js1);
}
[Ex04run.js]
const js1 = require('./Ex04js1');
const js2 = require('./Ex04js2');
js1();
js2();
[Ex05nextTick.js]
setImmediate(()=>{ //3
//즉시 실행하고 싶을 때 권장하는 함수!
console.log('immediate!');
})
setTimeout(()=>{ //2
console.log('timeout');
},0);
process.nextTick(()=>{ //1. 이벤트루프가 다른 함수보다 우선으로 처리하도록 만듬
console.log('nextTick');
});
[Ex06exit.js]
let i = 1;
setInterval(()=>{
if(i===5){
console.log('종료!');
process.exit();
}
console.log(i);
i++;
},1000);
[Ex07url.js]
const {URL} = require('url');
// url 생성자 활용
const myURL = new URL('https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=%EC%9B%94%EB%93%9C%EC%BB%B5+%EC%9D%BC%EC%A0%95');
console.log('searchParams : ', myURL.searchParams); //url의 전체 쿼리 확인
console.log('searchParams.get() : ', myURL.searchParams.get('query')); //특정 키의 값
//colors=red,blue,orange
//getAll(): 값이 여러개 일경우 전부 가져오기
console.log('searchParams.has() : ', myURL.searchParams.has('page'));// 특정 키를 가지고 있는지 확인(true/false)
console.log('searchParams.keys():', myURL.searchParams.keys()); //쿼리의 모든 키값
console.log('searchParams.values() :', myURL.searchParams.values()); //쿼리의 모든 벨루값
myURL.searchParams.append('key', 'value');
myURL.searchParams.append('key','value2');
console.log(myURL.searchParams.getAll('key')); // value1, value2
myURL.searchParams.set('key', 'value3');
console.log(myURL.searchParams.getAll('key')); //value3
myURL.searchParams.delete('key');
console.log(myURL.searchParams.getAll('key'));
console.log('searchParams.toString(): ', myURL.searchParams.toString());
myURL.search = myURL.searchParams.toString();
[Ex08crypto.js]
const crypto = require('crypto');
//1. 단방향 암호화: 복화할 수 없는 암호화 방식(해시함수)
//pbkdf2 <- node에서 지원하는 비밀번호 암호화 알고리즘
//salt 라고 불리는 문자열을 붙인 후 해시 알고리즘을 반복해서 적용
//64바이트 길이 문자열 생성
crypto.randomBytes(64, (err, buf)=>{
const salt = buf.toString('base64');
console.log('salt: ', salt);
//비밀번호, salt, 적용 반복 횟수, 출력바이트, 해시알고리즘
crypto.pbkdf2('password123',salt, 100000, 64, 'sha512', (err, key)=>{
console.log('패스워드 : ', key.toString('base64'));
})
})
//2. 양방향 암호화: 암호화된 문자열을 복호화 할 수 있음, 키가 사용됨
const algorithm = 'aes-256-cbc';
const key = 'abcdefghijklmnopqrstuvwxtz123456';
const iv = '1234567890123456'; //암호화 시 사용되는 초기화 벡터
const cipher = crypto.createCipheriv(algorithm, key, iv);
//암호화할 문장, 인코딩, 출력인코딩(출력바이트)
let result = cipher.update('암호화할 문장', 'utf-8', 'base64');
result += cipher.final('base64'); //마지막에 출력 결과물 인코딩 넣으면 암호화 완료
console.log('암호화:',result);
const decipher = crypto.createDecipheriv(algorithm, key, iv);
//인코딩 값 순서는 암호화 때 작성한 순서 반대로!
let result2 = decipher.update(result, 'base64', 'utf-8');
result2 += decipher.final('utf-8');
console.log("복호화 : ", result2);
[Ex03FileSystem]
[Ex01readFile.js]
const fs = require('fs');
fs.readFile('./readme.txt' , (err, data)=>{
if(err){ // 에러 발생시 예외처리
throw err;
}
console.log(data); //결과물은 buffer(메모리에 저장된 데이터) 형식으로 제공
console.log(data.toString());
})
[Ex02readFilePromise.js]
const fs = require('fs').promises;
//fs 모듈을 promise 형식으로 바꿔서 사용(비동기방식)
fs.readFile('./readme.txt')
.then((data)=>{ //buffer
console.log(data.toString());
})
.catch((err)=>{
console.error(err);
})
[Ex03writeFile.js]
const fs = require('fs').promises;
fs.writeFile('./writeme.txt', '새로 만든 파일!') //파일 생성
.then(()=>{ //파일이 생성이 성공하면
return fs.readFile('./writeme.txt');
})
.then((data)=>{ //파일 리턴 성공
console.log(data.toString());
})
.catch((err)=>{
console.log(err);
})
[readme.txt]
readme 파일입니다!
[writeme.txt]
새로 만든 파일!
[노드 내장 객체 알아보기]
global 브라우저의 window와 같은 전역 객체/ 모든 파일에서 접근 가능/ window와 같이 생략 가능
node 에는 DOM, BOM 이 없으므로 window와 document 객체는 사용할 수 없음
console global
[타이머]
setTimeout: 주어진 밀리초
[노드 내장 모듈 알아보기]
os : 운영체제의 정보 , 가져올 수있는 모듈
path: 폴더와 파일의 경로를 쉽게 조작하도록 도와주는 모듈
url: 인터넷
암호화 단방향(암호화)헷/ 양방향
<오후수업 코틀린>
<ex00입력>
package ex20221121
import java.util.*
fun main() {
//입력하는 도구를 가져오는 방법
//Scanner sc = new Scanner(System.in)
val sc = Scanner(System.`in`)
//readLine() 사용해서 런창에 입력할 수 있다
println("readLine()을 반드시 입력해야합니다 >> ")
var num1 = readLine()?.toInt()
// readLine은 무조건 String? 타입을 리턴
//1. null이 발생할 수 있는 상황에 대해서 조건식 부여
if (num1 != null) {
print(num1 + 2)
}
// 2. Elvis 연산자
// print(num1?.plus(2) ? : 실행 코드, 데이터 값)
// 3.
// println(num1!! +2)
// ? x
}
<Ex00 입력>
package ex20221121
import java.util.*
fun main() {
//입력하는 도구를 가져오는 방법
//Scanner sc = new Scanner(System.in)
val sc = Scanner(System.`in`)
//readLine() 사용해서 런창에 입력할 수 있다
println("readLine()을 반드시 입력해야합니다 >> ")
var num1 = readLine()?.toInt()
// readLine은 무조건 String? 타입을 리턴
//1. null이 발생할 수 있는 상황에 대해서 조건식 부여
if (num1 != null) {
print(num1 + 2)
}
// 2. Elvis 연산자
// print(num1?.plus(2) ? : 실행 코드, 데이터 값)
// 3.
// println(num1!! +2)
// ? x
}
<Ex01 산술연산자>
package ex20221121
fun main() {
// 1) 산술 연산자 : +,-, *, /, %
val num1 = 30
val num2 = 15
var result: Int
result = num1 + num2
println("+: $result")
result = num1 - num2
println("-: $result")
result = num1 * num2
println("*: $result")
result = num1 / num2 //0 -> by zero Exception 발생
//num2가 0이 아님을 확인하세요!
println("/: $result")
result = num1 % num2
println("%: $result") // 0 -> by zero Exception 발생
}
<Ex02 대입연산자>
package ex20221121
fun main() {
//1) 대입 연산자 (=)
//🍎🍎🍎🍎🍎🍎 -> window + .
var numOfApple =6 //현재 사과의 갯수
//2) 복합 대입연산자 ( +=, -=, *=, /=, %= )
//🍎🍎🍎🍎🍎🍎🍎🍎
// numOfApple = numOfApple + 2
numOfApple +=2
// 값을 누적시킬 때!
numOfApple -=2
}
<Ex03증감연산자>
package ex20221121
fun main() {
//3) 증감 연산자 ( ++,--)
// num ++, num -- : 후치 연산자: 코드가 실행된 후 +1
// ++num, --num : 전치 연산자: +1이 된 후 코드 실행
var num =1
println(num++) // 1
println(num) // 2
println(++num) // 3
println(num) // 3
println(num--) // 3
println(num) // 2
println(--num)// 1
println(num) // 1
}
<ex04비교연산자>
package ex20221121
fun main() {
val a: Int = 128
val b = a
println(a === b)
// ===: 참조값(주소값)이 동일한지 비교하는 연산자
val c: Int? = a
val d: Int? = a
val e: Int? = c
println(c == d)
println(c === d)
println(c === e)
}
<ex05 논리연산자>
package ex20221121
fun main() {
//5) 논리 연산자 : && , ||, !
// &&
//: 양쪽 항이 모두 true 일 경우 결과 값으로 true를 돌려준다.
// ||
// : 하나라도 true일 경우 결과값으로 true를 돌려준다.
//! (not)
// : 부정연산자
// !true --->false
}
<ex06 엘비스연산자>
package ex20221121
fun main() {
// 앨비스 연산자 ( ? : )
// NPE 발생을 예방할 수 있도록 NULL 값을 처리 해주는 연산자
var str: String? = null
print(str?.length?:"null입니다")
var result = str?.length?: -1
}
제어문: 프로그램 실행 흐름을 개발자가 원하는 방향으로 바꿀 수 있도록 해두는 것
<ex07조건문>
package ex20221121
fun main() {
// 단순 if (만약에 ~하면 ~ 한다)
val gender = "여"
if(gender =="여") println("여자입니다.")
// val result2 = if(gender == "여") "여자입니다."
// if(조건식) else
if (gender == "여") println("여자입니다.") else println("남자입니다.")
val result = if(gender == "여") "여자입니다." else "남자입니다."
println(result)
}
<ex08예제>
package ex20221121
import java.lang.NumberFormatException
import java.util.*
import kotlin.random.Random
import kotlin.random.nextInt
fun main() {
// 랜덤한 수를 가져올수있는 기능
// Random rd = new Random();
val rd = Random
// 입력하는 도구 가져오기
val sc = Scanner(System.`in`)
// sc.nextInt()
// 1. 랜덤한 두 수를 생성하자
var num1 = rd.nextInt(10)+1 //1~10 랜덤한 수 생성
var num2 = rd.nextInt(10)+1
//2. 랜덤한 두 수를 출력하자
println("$num1 + $num2 = ?")
//Kotlin에서는 같은자료형이랑 만! 연산이 가능하다
//3. 사용자로부터 정답입력 받기
print("Enter the Answer : ")
//val answer = readLine()?.toInt() ?:-1
//readLne(): String?
// readLine을 사용하게되면 사용자는 아무 문자/숫자가 입력가능한 상태
// toInt --> "1234" 사용자가 무조건 숫자를 입력해야 형변환이 가능
try{
val answer = readLine()?.toInt()
// 4. 사용자가 입력한 정답 == num1+num2 값 비교
val result = if(num1 + num2 == answer) "정답입니다. " else "오답입니다."
println("결과: $result")
}catch (e: NumberFormatException){
println("숫자를 입력해주세요! 문자는 입력할 수 없습니다.")
}
// Exception 잡는 방법
// try catch ---> 예외상황
}
<ex09 when 문>
package ex20221121
fun main() {
// when문 : Java에서 switch문과 동일
// when(변수){
// 값1 -> 실행코드1
// 값2 -> 실행코드2
// .........
// else -> 실행코드n
// }
val a = 2
when(a){
// 여러가지 값의 실행코드가 같을 경우
// a가 1또는 2일 경우 -> 실행코드를 실행
1,2 -> println("a는 1,2입니다.")
// 2 -> println("a는 1,2입니다.")
else -> println("a는 1,2가 아닙니다.")
}
// 식
when(a%2){
1 -> println("홀수입니다.")
0 -> println("짝수입니다.")
else -> println("")
}
//in .. (범위를 설정하는 키워드)
when(a){
in 0.. 10 -> println("0~10")
in 11..20 -> println("11~20")
else -> println(a)
}
//객체/변수의 데이터 타입을 확인할때 가장많이 사용합니다.!!!
// Any , is, when
//is : 데이터 타입 확인 사용하는 키워드
// Any: Java Object (최상위 클래스)
// when: 조건식의 일종
//반복문
//**함수
// +람다식
}
'Full Stack 교육 회고록' 카테고리의 다른 글
11/23 - kotlin, 안드로이드 스튜디오, node.js (0) | 2022.11.23 |
---|---|
11/22- kotlin / Node.js (0) | 2022.11.22 |
11/18 - Kotlin, (0) | 2022.11.18 |
10/20 - 프로젝트 시작(프론트엔드) (0) | 2022.11.12 |
2022년 웹 개발 로드맵 총정리 (공부순서 알려드림) (0) | 2022.10.29 |