허선생님의 귀중한 강의를 듣고 정리해 본 노드 포스팅!
썸네일의 잎사귀는 노드 느낌 나서 뙇!
우리 허선생님은 찰떡같이 가르치셨으나, 학생(나 ㅋㅋㅋ)이 못 알아듣고 왜곡해서 이상한 말을 썼을 수도 있음..👉👈
Node.js 특징 && 장점쓰
node.js는 프레임워크가 아니라 언어다. 자바스크립트의 구현체 중 하나이다.
특정 상황에서 수학 계산보단 입출력이 많을때 좋은 언어이다.
파일을 읽고 쓰고..할때! 데이터베이스 접근을 자주 할 때 좋다!
크롬엔 없지만 노드에만 있는 기능으론 app path가 있어서 파일 입출력을 노드가 컨트롤 할 수 있다.
대신 윈도우와 관련된건 없…!
그래도 자바스크립트 문법을 대부분 따른다는게 JS를 공부한 나에겐 가장 큰 장점쓰!
윈도우 관련된 기능 없으면 뭐어때! http관련된 기능이 노드에 기본적으로 들어가 있다.
blocking 과 none blocking io
흔히 말하는 동기와 비동기에 대한 것이다!
동기(blocking i/o)
일반적인 웹서버를 생각해보자.
푸드트럭에서 일하는 사람이 전자레인지에서 음식 데펴서 손님에게 준다고 생각해보자!
전자렌지를 돌리는 동안 똘똘한 사람들이라면 다른 음식을 조리하거나 음식을 주문받을텐데 동기는 그렇게 작동하지 않는다.
(내가 보기엔 비효율적이지만 분명 뭔가 장점이 있겠지)
다른 행동을 하지 않고 오로지 전자레인지 앞에서 음식이 다 조리 될때까지 기다린다ㅠㅠ Python이 대표적인 동기방식이라고 한다!
비동기(non blocking i/o)
컴잘알이 아닌 내가 보기엔 동기보다 똘똘한 방식.
전자레인지에 음식 집어넣고 기다리는 동안 다른 일을 한다. 똑똑해~
전자레인지 앞에서 대기타는 일처럼 코드상에서 신경쓰지 않고 넘어가도 되는 작업들을 넘겨버리는 게 바로 비동기라고 한다!
+ 여기서 잠깐 multi thread 이야기!
(single thread와 multi thread에 대해선 나중에 한번 정리하고 넘어갈 예정)
그림과 같이 컴퓨터가 다섯 대 있다고 쳐보자. 그렇다면 서버도 그에 맞게 다섯 개가 필요함
근데 내가 돌리는 컴퓨터 개수보다 접속자수가 많아지면 그게 동기방식으로 처리가 되서 비효율적이게 된다~
데이터베이스가 놀고 있어서 웹 서버는 강제로 휴식중..
빨리 일 시켜야 하는데 서버에서도 데이터 베이스를 기다리느라 아무것도 안하게 되는데…
이러한 현상을 해결하기 위한게 바로 비동기 처리 방식이다!
서버가 멍때리고 기다리는게 아니라 그때그때 계산해서 할 수 있는 행동을 전부 처리한다!
기다려야 하는 행동은 놔두고 먼저 처리할 수 있는 일을 처리하는 것
허선생님 진짜 찰떡같은 비유 최고..! 박수~~ 👏👏👏
여튼 react에서의 axios나 fetch가 바로 이런 비동기 처리방식이다!
실습해보자!
- 빈 폴더 하나 만들어서 초기화해준다. 명령어는
npm init
react 프로젝트 만들땐 -y를 붙였는데 이걸 안 붙이면
이렇게 값들을 하나 하나 설정을 해줘야 한다.
그래서 -y는 모두 yes를 뜻하는 것..!
여튼 이 과정을 통해 package.json 파일이 생성된다.
- server.js 파일을 만든다.
// server.js
let foo = 2;
console.log(foo);
터미널에 node server
명령어를 입력하면 콘솔에 2가 뜬다.
- app.js 파일도 만들어준다.
const http = require('http');
const app = require('./app');
// 경로를 안 붙이면 module이라고 생각하고, 경로를 붙이면 파일이라고 생각하면 됨
// listener를 가지고 있으면 app으로서 작동을 함.
http.createServer(app).listen(8000, () => {
console.log('서버 시작할게유~');
});
// inbound 요청을 듣겠다. 리쓴
// 듣기 시작한 이후에 콘솔찍겠다
- express 설치
명령어는yarn add express
입력 궈궈!
아직 express.js에 대해 잘은 모르지만 일단 해본다. 나중에 정리할 예정쓰!
const express = require('express');
const app = express();
// express는 class 인데 한번 더 묶어서 클래스처럼 안 보인다.
console.log('4');
app.get('/foo', () => {
console.log('요청을 받았다 오바!');
});
module.exports = app;
지금 app.js에 콘솔로 4를 찍고 있는데 그 전에 server.js에도 숫자를 찍어놨다.
console.log('1');
const http = require('http');
const app = require('./app');
// 경로를 안 붙이면 module이라고 생각하고, 경로를 붙이면 파일이라고 생각하면 됨
// listener를 가지고 있으면 app으로서 작동을 함.
console.log('2');
http.createServer(app).listen(8000, () => {
console.log('3');
console.log('서버 시작할게유~');
// 비동기 코드라 가장 늦게 실행됨
});
// inbound 요청을 듣겠다. 리쓴
// 듣기 시작한 이후에 콘솔찍겠다
console.log('5');
- server.js에서 서버가 시작되는 거니까 첫줄의 1이 가장 먼저 찍히고,
- server.js에 있는 app require를 실행하기 위해
module.exports = app;
위의 코드를 먼저 실행
그래서 app.js에서 값을 불러오니까 app에 있는 4가 두번째로 찍히고, - 그 다음 줄부터는 순서대로 찍힌다. (숫자 4까지 있을 때)
근데 마지막 줄에 5가 있으면 어떻게 될까?
5는 가장 마지막 줄에 있지만 createServer함수가 비동기 방식으로 인자로 들어간 함수를 받기 때문에
인자로 들어간 함수 안의 콘솔들이 가장 늦게 찍힌다.
그리하여 콘솔찍히는 순서는 1-4-2-5-3-서버 시작할게유~ 순!
콘솔창에는 값이 잘 찍히고 있는데, 문제는 웹페이지이다!
localhost:8000으로 접속해보면…
요청을 받았기 때문에 서버에는(터미널에는) 콘솔 값이 찍히는데 웹페이지가 안뜬다!
크롭탭만 봐도 뭔가 돌고 있는데.. 아무것도 뜨지 않는다.
일단 서버를 재시작(ctrl+c) 해야하는데, 그것보다 좀 더 효율적인 방법으로 nodemon을 깔아준다.
가라 노드몬!
- 설치는
npm i nodemon
- package.json에 start script를 추가해준다.
{
"name": "node-1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npx nodemon ./server"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"nodemon": "^2.0.1"
}
}
다시 한번 웹페이지를 확인해주는데…
흰 화면이 뜨는데 걍 흰색.. 내 요청을 씹은거다 ㅠㅠ
node에서 string, object, error 넘기기
이번엔 명령어를 입력해보자.
// app.js
app.get('/foo', (req, res, next) => {
res.send('배고파');
});
그랬더니 뙇! 임의의 태그가 생겼다!!
그냥 string으로 써서 일단 이런 임시 태그가 body에 생기는 것이고..
이번엔 json형태로 써보자.
// app.js
app.get('/foo', (req, res, next) => {
res.json({ 둘둘쓰: '배곱' });
});
짠!! 객체형태의 값이 화면에 나온다. 이렇게
나는 chrome json.viewer extension을 쓰고 있어서 예쁘게 나왔는데
원래대로라면 정말 날 것 그대로 나온다.
에러도 한 번 내보자! 참고로 4로 시작한건 일부러 내는 에러..ㅋㅋ
// app.js
app.get('/foo', (req, res, next) => {
res.status(401).json({ 둘둘쓰: '배곱' });
});
에러도 아주 잘 나고 있다. 좋았어!
Router
이번엔 라우팅을 위한 코드를 쳐볼거다.
const express = require('express');
const app = express();
app.get('/foo', (req, res, next) => {
// res.status(401).json({ 둘둘쓰: '배곱' });
});
app.get('/user', (req, res, next) => {
res.status(200).json({ name: '유저 목록' });
});
app.get('/user/:id', (req, res, next) => {
const id = req.params;
console.log(id);
res.status(200).json({
name: '허선생님',
id,
}); // 원래는 id: id 인데, 객체 값과 프로퍼티가 동일하면 지워짐. 놀라운 세상!
});
module.exports = app;
주소창에 http://localhost:8000/user?page=222&offset=20
를 쳐보면
짠~ 페이지에 json형태로 데이터가 잘 나오고 있고!
짠~ 콘솔창에 page와 offset 정보가 잘 나오고 있고!
Middleware
지난번에 비선실세 같은 존재라고 이해하고 넘어갔는데.. 막 그런건 아닌거 같고 ㅋㅋ app.get()<=== 이게 라우터고 라우터의 괄호안에 들어가는 게 바로 미들웨어다!
라우터는 실행할지 말지를 정해주는 역할이고, 미들웨어는 요청이나 응답이 들어오면 그걸 처리하는 함수다. 알고보니 비선실세는 라우터..
app.get();
app.post();
app.use();
app.all();
위와 같이 다양한 방식의 명령어가 있는데
그중에 app.use()는 유일하게 url을 쓰지 않아도 함수를 쓸 수 있다!
app.all()은 CRUD 네 가지 메소드 중 아무거나 접근을 하겠다는 것.
일단 배운 내용에 대해 여기까지 정리해봤는데..
허선생님께서 알기 쉽게 핵심만 쏙쏙 설명해주셔서 정말 감동쓰ㅠㅠ 감사합니다~
일단 코드를 쳐보면 좀 더 감이 오겠지? 화이팅 화이팅~~~