1장 노드 시작하기
1.1 핵심 개념 이해하기
1.1.1 서버
- 서버: 네트워크를 통해 클라이언트에 정보나 서비스를 제공하는 컴퓨터 또는 프로그램
- 클라이언트 → 서버 (요청) ⎮ 서버 → 클라이언트 (응답)
1.1.2 자바스크립트 런타임
- Node.js: Chrome V8 Javascript 엔진으로 빌드된 자바스크립트 런타임 (자바스크립트 실행기)
* 런타임: 특정 언어로 만든 프로그램을 실행할 수 있는 환경
- 노드는 V8, libuv(C, C++로 구현) 라는 라이브러리 사용
- libuv 라이브러리: 이벤트 기반, 논블로킹 I/O 모델 구현 (노드의 특성)
1.1.3 이벤트 기반
- 이벤트 기반: 이벤트(클릭, 네트워크 요청 등) 가 발생할 때 미리 지정해둔 작업을 수행하는 방식
- 이벤트 리스너에 콜백 함수 등록
- 이벤트 발생 (시스템 -> 이벤트 리스너)
- 등록된 콜백 함수 호출 (이벤트 리스너 -> 시스템)
- 호출 스택
(* anonymous 함수: 처음 실행 시의 전역 콘텍스트를 의미,
실행되는 동안 호출 스택에 머물러 있다가 실행이 완료되면 호출 스택에서 지워짐
* 콘텍스트: 함수가 호출되었을 때 생성되는 환경)
- 이벤트 루프: 이벤트 발생 시 호출할 콜백 함수들 관리, 호출된 콜백 함수의 실행 순서 결정
- 백그라운드: 타이머나 이벤트 리스너들이 대기하는 곳, 여러 작업 동시 실행 가능
- 테스크 큐: 이벤트 발생 후, 백그라운드에서 태스크 큐로 타이머나 이벤트 리스너의 콜백 함수를 보냄
Ex)
- 호출 스택에 쌓임
- setTimeout 실행 시 콜백 run은 백그라운드로 보냄
- 백그라운드에서 3초 후 태스크 큐로 보냄
- 호출 스택 실행이 끝나 비워지면
- 이벤트 루프가 태스크 큐의 콜백을 호출 스택으로 올림
- run이 호출 스택에서 실행되고 제거됨
- 이벤트 루프는 태스크 큐에 콜백이 들어올 때까지 대기
But, 호출 스택에 함수가 너무 많이 들어 있으면 3초가 지난 후에도 run 함수가 실행되지 않을 수도 있음
→ setTimeout의 시간이 정확하지 않을 수도 있는 이유
1.1.4 논블로킹 I/O
- 작업: 동시 실행 가능 작업(I/O 작업), 동시 실행 불가능 작업(자바스크립트 코드)
- I/O(Input 입력/Output 출력)
Ex) 파일 시스템 접근, 네트워크를 통한 요청 작업 등 → 이러한 작업들에 대해 노드는 논블로킹으로 처리하는 방법 제공
* 논블로킹: 이전 작업이 완료될 때까지 대기하지 않고 다음 작업을 수행
* 블로킹: 이전 작업이 끝나야만 다음 작업을 수행하는 것을 의미
→ 논블로킹이 같은 작업을 더 짧은 시간에 처리 (전제: 모두 동시에 처리될 수 있는 작업이어야 함)
- 노드는 I/O 작업을 백그라운드로 넘겨 동시에 처리 → 시간 절약 가능
- setTimeout(콜백, 0): 논블로킹으로 만들기 위해 사용하는 기법
* 노드에서 동기 - 블로킹, 비동기 -논블로킹이 유사
1.1.5 싱글 스레드
- 싱글 스레드: 스레드가 하나뿐인 것
- 프로세스: 운영체제에서 할당하는 작업의 단위, 프로세스 간에는 메모리 공유 x
- 스레드: 프로세스 내에서 실행되는 흐름의 단위, 프로세스는 스레드를 여러 개 생성
→ 여러 작업 동시 처리, 같은 주소의 메모리에 접근 가능
→ 데이터 공유
1.2 서버로서의 노드
- 노드 서버의 특성
- 노드와 마찬가지로 노드 서버 또한 싱글 스레드, 논블로킹 모델 사용
- 서버는 기본적으로 I/O요청이 많이 발생 → I/O 처리를 잘하는 노드를 서버로 사용하면 좋음
- 노드(가정: 논블로킹 방식으로 코드 작성) : libuv 라이브러리를 사용해 I/O 작업을 논블로킹 방식으로 처리
But, CPU 부하가 큰 작업은 스레드 하나가 혼자서 감당하기 어려움
따라서, 노드는 개수는 많지만 크기는 작은 데이터를 실시간으로 주고 받는데 적합 (네트워크, 데이터베이스, 디스크 작업)
Ex) 채팅 어플리케이션, 주식 차트, API 서버에서 노드를 많이 사용
- 노드 서버의 장단점
장점 | 단점 |
|
|
1.3 서버 외의 노드
- 노드는 자바스크립트 런타임으로 용도가 서버뿐만 아니라 웹, 모바일, 데스크톱 애플리케이션 개발에도 사용됨
- 노드 기반 웹 프레임워크 - 앵귤러(구글), 리액트(페이스북), 뷰
모바일 개발 도구 - 리액트 네이티브
데스크톱 개발 도구 - 일렉트론
2장 알아둬야 할 자바스크립트
2.1 ES2015+
- ES2015+ : ES2015 이상의 자바스크립트를 통틀어 표현
2.1.1 const, let
- var: 함수 스코프를 가지므로 if문의 블록과 관계없이 접근 가능
- const, let: 블록 스코프를 가지므로 블록 밖에서는 변수에 접근 불가능 블록 스코프 사용 → 호이스팅 문제 해결, 코드 관리 수월해짐
- const, let의 차이: const는 한 번 값을 할당하면 다른 값을 할당할 수 없음, 상수
if (true) {
var x = 3;
}
console.log(x); // 3
if (true) {
const y = 3;
}
console.log(y); // ReferenceError
2.1.2 템플릿 문자열
- 백틱(`): 문자열 안에 변수를 넣을 수 있음, ${변수} 형식
const num3 = 1;
const num4 = 2;
const result2 = 3;
const string2 = `${num3} 더하기 ${num4}는 ' ${result2}'`;
console.log(string2); // 1 더하기 2는 '3'
2.1.3 객체 리터럴
- 객체의 메서드에 함수를 연결할 때 더는 콜론(:)과 function 을 붙이지 않아도 됨
const newObject = {
sayJS() {
console.log('JS');
},
sayNode,
[es + 6]: 'Fantastic',
};
newObject.sayNode(); // Node
newObject.sayJS(); // JS
console.log(newObject.ES6); // Fantastic
- 속성명과 변수명이 동일한 경우 한 번만 써도 됨
{ name: name, age: age } // ES5
{ name, age } // ES2015
2.1.4 화살표 함수
- 화살표 함수에서는 function 선언 대신 => 기호로 함수 선언
const add2 = (x, y) => {
return x + y;
};
- 화살표 함수에서는 내부에 return문밖에 없는 경우 return할 식을 바로 적으면 됨
const add3 = (x, y) => x + y;
- 기존 function과 다른 점: this 바인드 방식
const relationship2 = {
name: 'zero',
friends: ['nero', 'hero', 'xero'],
logFriends() {
this.friends.forEach(friend => {
console.log(this.name, friend);
});
},
};
relationship2.logFriends();
- this를 사용해야 하는 경우에는 화살표 함수와 함수 선언문 둘 중 하나를 고르면 됨
2.1.5 구조 분해 할당
- 구조 분해 할당 사용 → 객체와 배열로부터 속성이나 요소를 쉽게 꺼낼 수 있음
const candyMachine = {
status: {
name: 'node',
count: 5,
},
getCandy() {
this.status.count--;
return this.status.count;
},
};
const { getCandy, status: { count } } = candyMachine;
const array = [‘nodejs’, {}, 10, true];
const [node, obj, , bool] = array;
2.1.6 클래스
- 클래스 기반으로 동작하는 것이 아닌 프로토타입 기반으로 동작하지만 프로토타입 기반 문법을 보기 좋게 클래스로 바꾼 것
class Human {
constructor(type = 'human') {
this.type = type;
}
static isHuman(human) {
return human instanceof Human;
}
breathe() {
alert('h-a-a-a-m');
}
}
class Zero extends Human {
constructor(type, firstName, lastName) {
super(type);
this.firstName = firstName;
this.lastName = lastName;
}
sayName() {
super.breathe();
alert(`${this.firstName} ${this.lastName}`);
}
}
const newZero = new Zero('human', 'Zero', 'Cho');
Human.isHuman(newZero); // true
2.1.7 프로미스
- 프로미스: 실행은 바로 하되 결괏값은 나중에 받는 객체
function findAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save();
})
.then((user) => {
return Users.findOne({ gender: 'm' });
})
.then((user) => {
// 생략
})
.catch(err => {
console.error(err);
});
}
- ES2015부터 자바스크립트와 노드의 API들이 콜백 대신 프로미스 기반으로 재구성
- 메서드가 프로미스 방식을 지원해야만 콜백 함수를 프로미스로 바꿀 수 있음
- Promise.all을 활용하여 프로미스 여러 개를 한 번에 실행
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
Promise.all([promise1, promise2])
.then((result) => {
console.log(result); // ['성공1', '성공2'];
})
.catch((error) => {
console.error(error);
});
- reject된 promise에 catch를 달지 않으면 에러가 발생하기 때문에 catch 메서드를 붙이는 것을 권장
try {
Promise.reject('에러');
} catch (e) {
console.error(e); // UnhandledPromiseRejection: This error originated either by throwing inside...
}
Promise.reject('에러').catch(() => {
// catch 메서드를 붙이면 에러가 발생하지 않음
})
2.1.8 async/await
- async/await 문법은 프로미스를 사용한 코드를 더 깔끔하게 줄임
async function findAndSaveUser(Users) {
let user = await Users.findOne({});
user.name = 'zero';
user = await user.save();
user = await Users.findOne({ gender: 'm' });
// 생략
}
- for문 + Async/await: 프로미스를 순차적으로 실행
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
(async () => {
for await (promise of [promise1, promise2]) {
console.log(promise);
}
})();
2.1.9 Map/Set
- Map: 객체와 유사, 속성들 간의 순서를 보장하고 반복문을 사용할 수 있음, size 메서드를 통해 속성의 수를 쉽게 알 수 있음
const s = new Set();
s.add(false); // add(요소)로 Set에 추가
s.add(1);
s.add('1');
s.add(1); // 중복이므로 무시됨
s.add(2);
console.log(s.size); // 중복이 제거되어 4
s.has(1); // has(요소)로 요소 존재 여부를 확인
console.log(s.has(1)); // true
for (const a of s) {
console.log(a); // false 1 '1' 2
}
s.forEach((a) => {
console.log(a); // false 1 '1' 2
})
s.delete(2); // delete(요소)로 요소를 제거
s.clear(); // clear()로 전부 제거
- Set: 배열과 유사, 중복을 허용하지 않음, 배열 자료구조를 사용하고 싶지만 중복은 허용하고 싶지 않을 때 사용
const arr = [1, 3, 2, 7, 2, 6, 3, 5];
const s = new Set(arr);
const result = Array.from(s);
console.log(result); // 1, 3, 2, 7, , 5
- new Set(배열): 배열의 중복된 요소들 제거
- Array.from(Set): Set을 배열로 되돌림
2.1.10 널 병합/옵셔널 체이닝
- ??(널 병합) 연산자: || 연산자 대용으로 사용,
falsy값(0, ‘’, false, NaN, null, undefined)중 null과 undefined만 따로 구분,
null이나 undefined의 속성을 조회하는 경우 에러가 발생하는 것을 막음
const a = 0;
const b = a || 3; // || 연산자는 falsy 값이면 뒤로 넘어감
console.log(b); // 3
const c = 0;
const d = c ?? 3; // ?? 연산자는 null과 undefined일 때만 뒤로 넘어감
console.log(d); // 0;
const e = null;
const f = e ?? 3;
console.log(f); // 3;
const g = undefined;
const h = g ?? 3;
console.log(h); // 3;
- ?.(옵셔널 체이닝) 연산자: TypeError: Cannot read properties of undefined 또는 null 에러의 발생 빈도를 획기적으로 낮출 수 있어
자주 사용
const a = {}
a.b; // a가 객체이므로 문제없음
const c = null;
try {
c.d;
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading 'd')
}
c?.d; // 문제없음
try {
c.f();
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading 'f')
}
c?.f(); // 문제없음
try {
c[0];
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading '0')
}
c?.[0]; // 문제없음
2.2 프런트엔드 자바스크립트
2.2.1 AJAX
- AJAX: 비동기적 웹 서비스를 개발할 때 사용하는 기법, 페이지 이동 벗이 서버에 요청을 보내고 응답을 받는 기술
- GET 요청: axios.get 함수의 인수로 요청을 보낼 주소를 넣으면 됨, axios.get을 사용
axios.get('https://www.zerocho.com/api/get')
.then((result) => {
console.log(result);
console.log(result.data); // {}
})
.catch((error) => {
console.error(error);
});
- POST 방식의 요청: 데이터를 서버로 보낼수 있음, axios.post를 사용
(async () => {
try {
const result = await axios.post('https://www.zerocho.com/api/post/json', {
name: 'zerocho',
birth: 1994,
});
console.log(result);
console.log(result.data);
} catch (error) {
console.error(error);
}
})();
- AJAX 요청은 jQuery, axis 같은 라이브러리를 이용해서 보냄
2.2.2 FormData
- HTML form 태그의 데이터를 동적으로 제어할 수 있는 기능, AJAX와 주로 함께 사용
2.2.3 encodeURIComponent, decodeURIComponent
- 서버가 한글 주소를 이해하지 못하는 경우 window 객체의 메서드인 encodeURIComponent 메서드를 사용
- 한글 주소 부분만 encodeURIComponent 메서드로 감싸고 받는 쪽에서는 decodeURIComponent를 사용하면 됨
(async () => {
try {
const result = await axios.get(`https://www.zerocho.com/api/search/${encodeURIComponent('노드')}`);
console.log(result);
console.log(result.data); // {}
} catch (error) {
console.error(error);
}
})();
decodeURIComponent('%EB%85%B8%EB%93%9C'); // 노드
2.2.4 데이터 속성과 dataset
- 데이터 속성
: HTML과 관련된 데이터를 저장하는 공식적인 방법, HTML 태그의 속성으로, data-로 시작하는 것들을 넣음
dataset에 데이터를 넣어도 HTML 태그에 반영됨
'WINK-(Web & App) > Express.js (Node.js) 스터디' 카테고리의 다른 글
[2024 여름방학 Node.js 스터디] 김지나 #2주차 (3) | 2024.07.25 |
---|---|
[2024 여름방학 Node.js 스터디] 이종윤 #1주차 (0) | 2024.07.18 |
[2024 여름방학 Node.js 스터디] 김지나 #1주차 (0) | 2024.07.18 |
[2024 Node.js 스터디] 김수아 #4주차 "Node.js 6,7,9장" (0) | 2024.05.25 |
[2024 Node.js 스터디] 장민우 #5주차 "인생이란" (0) | 2024.05.25 |