개발 공부를 하면서 프론트, 백, 데브옵스처럼 커리어를 한정짓고 싶지 않았고 웹개발자라면 웹에서 발생하는 여러 문제들을 해결할 수 있는 역량이 필요하다고 생각했다. 그런 역량을 위해서는 웹 전반에 대해 이해할 수 있어야 한다.
하지만 생각처럼 백엔드 쪽 공부를 할 수 있는 상황이 잘 주어지지 않았다. 그래서 정글이 끝나면 가장 먼저 할 것으로 백엔드 공부를 생각했다. 그리고 이제서야 차근차근 배워나가게 되었다.
아시다시피 Node.js
는 자바스크립트를 브라우저에서 뿐만 아니라 그 밖에서도 쓸 수 있게 한다는 점이 장점이다. 그래서 백엔드 뿐만 아니라 여러 Automation 라이브러리를 구현할 수도 있어, 이번 기회에 여러가지 시도를 꿈꿔본다.
자아, 공부하러 가보자.
Node.js는
주요 4가지 특징을 가지고 있다. 이러한 특징을 통해 Sigle Thread
이지만 비동기
의 특징으로 I/O작업을 효율적으로 할 수 있게 된다.
자세한 내용은 전에 정리했던 Node.js 작동원리 포스팅을 확인해보자.
CRA를 하면 항상 자동으로 생성되는 거라서 별 생각이 없었다. 하지만 Node.js가 제공하는 여러 라이브러리를 담고 있기 때문에 매우 중요하다는 것을 한 번 더 생각할 수 있었다.
이 부분이 정글 마지막 프로젝트에서 나를 힘들게 했던 것이라 정확히 알고 싶었다.
라이브러리를 설치할 때, 구글링한 정보마다 module import하는 방법이 달라서 계속 오류가 나서 힘들었다.
export
[counter.js]
function getCount() {
return count;
}
module.exports.getCount = getCount;
import
[app.js]
const counter = require("./counter");
export
[counter.js]
export function getCount() {
return count;
}
package.json에 'type : module' 추가
{
"name": "5-module",
"version": "1.0.0",
"description": "",
"main": "app.js",
"type" : "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
import
[app.js]
import { getCount} from './counter.js'
node.js에서 제공하는 모듈을 통해 os, process에도 접근할 수 있다.
const os = require('os');
const process = require('require');
Timer 관련 모듈을 통해서 Call Stack
과 Task Queue
를 넘나들며 활용할 수 있다.
const process = require("process");
console.log(1);
console.log(2);
setTimeout(()=>{
console.log("setTimeOut")
},0)
process.nextTick(() => {
console.log("nextTick");
});
for (let i = 0; i < 10; i++) {
console.log('loop : ', i)
}
위의 식이 있을 때, 어떻게 발동할 지 예상해보자.
- 스크립트의 위에서부터
Call Stack
에 함수를 넣어 발동한다.- 이 때
SetTimeout
node module을 만나 0초 후에TaskQueue
에 콜백함수를 저장한다.process.nextTick(callback())
를 통해Task Queue
에 콜백함수를 저장하는데, 이 때 우선순위는 가장 먼저다.- 그리고 다시 for문을
Call Stack
에 넣어 모든 과정을 거친다.- for문이 모두 실행되면
Call Stack
이 비게 되는데, 이 때Task Queue
에 있던 함수들이 발동된다.Task Queue
에 쌓여있는 순서대로 Call Stack으로 옮겨가 발동된다.
즉, setTimeout(()=>{},0)
이라고 하더라도 0초 후에 발동하는 것이 아니다. Call Stack에 얼마나 크기 큰 함수가 있느냐에 따라 발동시간의 차이가 있다.
Node.js는 fileSystem에 접근하기 유리하다. 이렇게 fileSystem에 접근할 때 그 경로를 찾기 위해 path를 쓴다.
[app.js]
const path = require('path')
{
root: 'C:\\',
dir: 'C:\\Users\\Sehoon\\projects\\back_end_practice\\node\\9-path',
base: 'app.js',
ext: '.js',
name: 'app'
}
file 관련 node module에 대해 알아보자
rename : (비동기) 파일명 변경
const fs = require('fs')
[방법 1]
fs.rename('./a.txt', './b.txt', (err) => {
console.log(err)
})
[방법 2]
fs.promises
.rename("./text.txt", "/text-new.txt")
.then(() => {
console.log("DONE!");
})
.catch(console.error);
읽고, 쓰고, 복사하고, 디렉토리 만들고
const fs = require('fs').promises
fs.readFile('./text.txt', 'utf-8').then(
(data) => {console.log(data)})
.catch(console.error)
fs.writeFile("./file.txt", "Hello, Sehoon").catch();
fs.appendFile("./file.txt", "Yo, Sehoon")
.then(()=>{
fs.copyFile("./file.txt", './file2.txt')
}).catch();
fs.mkdir('sub-folder').catch(console.error)
fs.readdir('./').then(console.log).catch(console.error)
=> 안에 파일들이 배열로 나온다.
전체 메모리를 고정 크기로 토막내서 저장한 것으로 bye의 배열이다.
Buffer.from(string)
Buffer.alloc(number)
buf.toString()
buffer 생성
const buf = Buffer.from('Hi')
buffer 내에 유니코드가 배열 형식으로 나오게 된다.
buf[0]
, buf[1]
로도 접근 가능한데
이때는 ASCII 코드로 나온다.
buffer 다시 string으로
buf.toString()
buffer 공간 생성
const buf = Buffer.alloc(2)
buf[0] = 72
buf[1] = 105
console.log(buf.toString()) => 글자 나옴
Buffer.concat([buf1, buf2, buf3])
fs.createReadStream('읽을 파일 경로')
fs.createReadStream('./file.txt',)
.on('data' , chunk => {
data.push(chunk)
})
.on('error',console.error)
.on('end', () => {console.log(data.join(''))})
fs.createWriteStrea('새로 쓸 파일 경로')
const writeStream = fs.createWriteStream('./file.txt',)
.on('finish' , () => {console.log('finish')})
writeStream.write('HELLO')
wrtieStream.wrtie('SEhoon')
writeStream.end()
const zlib = require("zlib");
const zlibStream = zlib.createGzip();
const piping = readStream.pipe(zlibStream).pipe(writeStream);
piping.on("finish", () => {
console.log("done!");
});