Posts 노드 스터디 3장
Post
Cancel

노드 스터디 3장

Node 3장

REPL 사용하기

  • 노드 콘솔은 REPL이라하는데 이유는

    • Read : 입력한 코드를 읽고
    • Eval : 해석하고
    • Print : 결과물을 반환하고
    • Loop : 종료할 때가지 반복함.
  • 터미널에 node를 입력함으로서 접속가능
  • 간단한 명령어 수행

JS 파일 실행

  • helloworld.js 라는 파일을 만들었으면 node helloworld 로 접근할 수 있음

모듈로 만들기

  • 노드는 코드를 모듈로 만들 수 있다는 점에서 브라우저의 자바스크립트와는 다르다.

    • 크롬 60버전부터는 브라우저에서도 모듈을 사용할 수 있음
  • require(‘./var’); 로 불러오고, module.exports = 로 export함

    • 이때, 다른이름으로 불러올 수 있다.
    • 예를들어, module.exports = addTwoNum을 const addTwo = require(‘./temp’); 로 불러올 수 있음.
    • 단, 이때 ES6 이상의 문법에서 비구조화와 헷갈리지말자.
  • 자바스크립트 자체 모듈

    • import {odd, even} from ‘./var’;
    • export defualt checkOddOrEven
    • 이런 식으로 함.
    • export : 함수, 객체, 원시값을 내보낼때 사용
      • 받을땐 import {a, b, c, d} from ‘./temp’ 로 받음
    • exports : 함수, 객체, 원시값을 객체의 형태로 내보낼 때 사용
      1
      2
      3
      4
      5
      
      exports.a = "a";
      exports.b = "b";
      //이렇게 내보내고
      import importTemp from "./temp";
      //이렇게 받음. 이름은 달라도 됨. exports 객체를 받는 것이기에
      
    • exports default : 파일내에서 하나의 고정된 값만 내보낼때 사용

노드 내장객체

  • global
    • 브라우저의 window와 같은 전역객체
    • 모든 파일에서 접근가능
    • 이때 부를땐 global을 생략하고 부를 수있다.
      • ex) globa.require() -> require()
    • global 객체의 속성에 값을 대입하여 파일간 데이터를 공유할 수 있지만, 남용하지는 마라. 프로그램이 커질수록 어디서 넣었는지 찾기 힘들어져 유지보수가 어려워진다. 모듈형식으로 사용하라
  • console
    • console.log()
    • console.error()
    • console.time() - console.timeEnd()
      • time()부터 timeEnd()까지의 시간 출력
      • 이때 양쪽에 같은 레이블을 넣어, 레이블별로 구분가능하다.
    • console.table([{name:’제로’, birth:1994}, { name: ‘hero’, birth: 1988}])
      • 이런식으로 테이블을 만들 수도 있음
    • console.dir()
      • 객체를 출력하는데, 두번째 인자로 옵션을 넣어서 출력가능
    • console.trace()
      • 에러위치추적
  • 타이머
    • setTimeout(callback, milisec) : 주어진 milisec 이후에 콜백 함수 실행
    • setInterval(callback, milisec) : 주어진 milisec마다 콜백 실행
    • setImmediate(callback) : callback을 즉시 실행. 큐에있는 콜백이 실행 후 실행하도록 일단 큐에 넣는 것.
    • clearTimeout(id) : setTimeout에서 반환한 아이디를 넣어, 종료시키는 것
    • clearInterval(id) : 마찬가지
    • clearImmediate(id) : 마찬가지
    • setImmediate vs setTimeout(callback, 0)
      • 우선 setTimeout(callback, 0) 는 사용하지 않는걸 권장
      • 파일시스템 접근, 네트워킹 등 I/O 작업의 콜백함수 안에서 타이머를 호출하는 경우 setImmediate가 먼저 호출됨.
  • __filename, __dirname
    • 현재 파일의 경로나 파일명을 알아야할때 사용
    • console.log(__filename); 을 통해 현재 파일 경로를 알려줌
    • __dirname은 폴더까지만
    • 구분자 문제가 있어 보통은 path 모듈을 함께 사용함
  • module, exports, require
    • module.exports 대신 exports 단독으로 쓰일수있다.
      • exports.odd = “홀수입니다”
    • module.exports와 exports는 같은 객체, exports.add 이런식으로 exports객체를 만들면, 이것이 module.exports로 들어감.
      • 따라서 한 모듈에 두개 동시에 쓰지말자
    • require.cache : 한번 require한 파일이 저장됨. 다시 require할땐 여기있는 것을 불러옴.
    • require.main : 노드 실행시 첫모듈을 가리킴.
    • 순환참조가 발생할 경우, 대상을 빈 객체로 만듬.
  • this
    • 최상위 스코프에 있는 this는 module.exports 객체를 가리킴.
    • 함수 선언문 내부의 this는 global 객체를 가리킴
  • process
    • 현재 실행되고 있는 노드 프로세스의 정보를 담고 있음.
    • process.env
      • 시스템 환경변수
      • 비밀번호나 각종 API 키를 코드에 직접입력하는 대신 .env(dotenv)에 입력함
      • 코드에서 참조할땐 process.env.SECRET_KEY로 접근
    • process.nextTick(callback)
      • 이벤트루프가 다른 콜백함수보다 nextTick의 콜백함수를 우선으로 처리하도록 함.
    • process.exit(코드)
      • 0이면 정상 1이면 비정상
      • 프로세스 종료

노드 내장 모듈

  • os : os 관련 정보 및 에러와 신호에 대한 정보를 담음.
  • path : 폴더와 파일의 경로를 쉽게 조작하도록 도와주는 모듈
    • 운영체제별로 경로 구분자가 다르기에 필요함.
    • path.parse(경로) : 파일 경로를 root, dir, base, ext, name으로 분리함.
    • path.format(객체) : path.parse()한 객체를 파일경로로 합침.
    • path.normalize(경로) : 구분자를 실수로 사용했을때 정상적인 경로로 변환함.
  • url : 인터넷주소를 쉽게 조작하도록 도와주는 모듈
    • 두가지방식이 있음
      • WHATWG 방식의 url: 노드 버전 7부터 추가됨.
      • classic url
    • url 생성자 불러오기
      1
      2
      3
      
      const url = require("url");
      const { URL } = url; // WHATWG 방식의 생성자 들어감.
      const myURL = new URL("https://naver.com");
      
    • WHATWG 방식은 search부분을 searchParams로 반환하므로 편하다.
      • searchParams에서 여러 메소드가 존재함. 잘 찾아서 사용.
  • querystring
    • const qs = require(‘querystring’);
    • search 부분을 사용하기 쉽게 객체로 만드는 모듈
    • querystring.parse(쿼리) : url의 query부분을 넣고 객체로 분해함.
    • querystring.stringify(객체) : 분해된 query 객체를 문자열로 다시 조립함.
  • crypto
    • 다양한 방식의 암호화를 도와줌.
    • 단방향 암호화 알고리즘 == 복호화할수없는 암호화 == 해시함수
    • 해시기법 : 어떠한 문자열을 고정된 길이의 다른 문자열로 바꿔버림.
    • 사용법
      1
      2
      3
      4
      5
      
      const crypto = require("crypto");
      console.log(
        "base64",
        crypto.createHash("sha512").update("비밀번호").digest("base64")
      );
      
    • createHash(알고리즘) : 사용할 알고리즘을 넣음.
      • sha256, sha512
    • update(문자열) : 비밀번호
    • digest : 인코딩할 알고리즘을 넣음
      • base64, hex, latin1
    • 현재 주로사용하는 알고리즘 : pdkdf2, bcrypt, scrypt 등
    • pdkdf2 : 기존 문자열에 salt라고 불리는 문자열을 붙인 후에, 해시 알고리즘을 반복해서 적용
      1
      2
      3
      4
      5
      6
      7
      8
      
      //random으로 64바이트 문자열을 만듬.
      crypto.randomBytes(64, (err, buf) => {
        const salt = buf.toString("base64");
        //비밀번호, salt, 반복횟수, 출력바이트, 해시알고리즘 순으로 넣음.
        crypto.pbkdf2("비밀번호", salt, 100000, 64, "sha512", (err, key) => {
          console.log("password:", key.toString("base64"));
        });
      });
      
      • 10만번 해도 1초밖에 안걸림. 내부적으로 스레드풀을 사용해 멀티스레딩을 하기에, 블로킹 걱정x
    • 양방향암호화
      • 암호화된 문자열을 복호화할수 있으며, 키를 사용함. 같은키를 사용해야 복호화가능
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        
        const algorithm = "aes-256-cbc";
        const key = "abcdefghijklmnopqrstuvwxyz123456";
        const iv = "1234567890123456";
        //암호화
        const cipher = crypto.createCipheriv(algorithm, key, iv);
        let result = cipher.update("암호화할 문장", "utf8", "base64");
        result += cipher.final("base64");
        //복호화
        const decipher = crypto.createDecipheriv(algorithm, key, iv);
        let result2 = decipher.update(result, "base64", "utf8");
        result2 += decipher.final("utf8");
        
      • 사용가능한 알고리즘 목록은 crypto.getCiphers()를 호출하면 볼수있음.
  • util
    • util.deprecate(func, message) = 함수가 deprecated처리됐음을 알림.
    • util.promisify(func) : 콜백 함수를 프로미스패턴으로 바꿈. async/await 가능, then/catch가능
  • worker_threads
    • 노드에서 멀티스레드로 작업하는 방법
    • const {Worker, isMainThread, parentPort} = require(‘worker_threads’) 로 불러옴
    • isMainThread 메인 스레드에서 실행되는지 구분.
    • 부모에서는 워커생성 후 worker.postMessage로 데이터를 보낼 수 있음.
    • 자식에선 parentPort.on(‘message’) 로 메세지를 받음
  • child_process
    • 다른 프로그램을 실행하고 싶거나 명령어를 수행하고 싶을때 사용함.
    • 이 모듈을 통해 다른 언어의 코드(파이썬 등)을 실행하고 결과값을 받을 수 있음.
    • exec : 셀을 실행해서 명령어를 수행
    • spawn : 새로운 프로세스를 띄우면서 명령어를 실행함.
  • 기타모듈들
    • assert: 값을 비교하여 프로그램이 제대로 동작하는지 테스트하는 데 사용합니다.
    • dns: 도메인 이름에 대한 IP 주소를 얻어내는 데 사용합니다.
    • net: HTTP보다 로우 레벨인 TCP나 IPC 통신을 할 때 사용합니다.
    • string_decoder: 버퍼 데이터를 문자열로 바꾸는 데 사용합니다.
    • tls: TLS와 SSL에 관련된 작업을 할 때 사용합니다.
    • tty: 터미널과 관련된 작업을 할 때 사용합니다.
    • dgram: UDP와 관련된 작업을 할 때 사용합니다.
    • v8: V8 엔진에 직접 접근할 때 사용합니다.
    • vm: 가상 머신에 직접 접근할 때 사용합니다.

파일시스템 접근하기

  • fs 모듈. 파일시스템에 접근하는 모듈. 파일생성/삭제/read/write 가능
  • read : fs.readFile(‘경로’, callback)
    1
    2
    3
    4
    5
    6
    7
    8
    
    const fs = require("fs"); //require('fs').promises; 로하면 프로미스형태로 사용가능.
    fs.readFile("./readme.txt", (err, data) => {
      if (err) {
        throw err;
      }
      console.log(data); // 읽은 데이터는 버퍼형식으로 반환됨.
      console.log(data.toString()); // 읽을 수 없으므로 toString()으로 변환 시켜줌
    });
    
  • write : fs.writeFile(경로, 내용);

  • 동기 메소드와 비동기메소드

    • 동기메소드 : readFileSync, writeFileSync / 콜백함수대신에 직접 리턴값을 받아옴.
    • 비동기메소드 : readFile, writeFile / 명령이 실행되면 백그라운드에 해당파일을 읽으라고 요청하고 다음으로 넘어감.
    • 동기로 하게되면 요청이 처리되는 동안 메인스레드는 놀게됨.
    • 동기로 하되, 요청이 백그라운드에서 처리되도록 하려면, readFile을 사용하되 콜백안에서 다시 readFile을 실행하도록 한다. 이때 콜백지옥은 promises로 실행하면 해결할 수 있다.
  • 버퍼와 스트림

    • 노드는 파일을 일을때 메모리에 파일크기만큼 공간을 마련해두며 파일 데이터를 메모리에 저장한 뒤 사용자가 조작할 수 있도록 함.
    • 이때 메모리에 저장된 데이터가 버퍼
    • Buffer 클래스
      • 버퍼를 직접 다룰 수 있는 클래스
        1
        
        const buffer = Buffer.from("저를 버퍼로 바꾸세요");
        
      • .toString() : 문자열로 바꿈
      • .length : 길이
      • .concat() : 합치기
      • .alloc(바이트) : 빈 버퍼를 생성.
    • 버퍼의 단점 : 100MB 파일이 10개 필요하면 1GB 공간이 필요 -> 비효율 -> 따라서 버퍼의 크기를 작게만든 후 여러번으로 나눠보내는 방식이 탄생 -> 스트림
    • fs.createReadStream(path, option), fs.writeReadStream(path, option)

      • 나눠진 조각은 chunk라고 부름
      • option
        • highWaterMark : 버퍼의 크기를 정함.
      • readStream을 반환. 따라서 다음같이 작성
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      const readStream = fs.createReadStream("./readme3.txt", {
        highWaterMark: 16,
      });
      const data = [];
        
      readStream.on("data", (chunk) => {
        data.push(chunk);
        console.log("data :", chunk, chunk.length);
      });
      
      • 이벤트리스너
        • data : 읽기가 시작되면 방생
        • error : 읽다가 에러발생시
        • end : 다 읽으면
  • 기타 fs메소드

    • fs.access(경로, 옵션, 콜백) : 접근할 수 있는지
    • fs.mkdir(경로, 콜백)
    • fs.open(경로, 옵션, 콜백)
    • fs.rename(기존경로, 새경로, 콜백)
    • fs.readdir(경로, 콜백)
    • fs.unlink(경로, 콜백) : 파일을 지움
    • fs.rmdir(경로, 콜백) : 폴더를 지움
    • fs.watch(경로, 콜백) : 파일/폴더의 변경사항을 감시할 수 있음
      • change 이벤트는 두번 발생할 수 있으므로 주의
  • 스레드풀
    • 기본적인 스레드풀의 개수는 4개.
    • 처음 4개의 작업이 동시에 실행되고, 후에 4개가 실행
    • 스레드풀의 개수는 변경가능. 나중에 찾아서 함
    • 이때 스레드풀의 개수는 프로세서 코어의 개수와 같거나 많게 두어야 효과가 나옴

이벤트 이해하기

  • .on(‘data’, 콜백) 이렇게 이벤트리스너를 등록할 수 있음.
  • .addListener(이벤트, 콜백) 이것도 가능
  • .emit(이벤트) : 이벤트 호출
  • .removeListener(이벤트, 콜백) : 삭제
  • .removeAllListener(이벤트) : 이 이벤트에 연결된 모든 콜백 삭제
  • .listenerCount(이벤트)

예외처리

  • try-catch
  • 노드내장 모듈의 에러는 실행중인 프로세스를 멈추지 않음. 에러로그를 기록함.
  • throw : 발생시 노드 프로세스 중지. 반드시 try-catch로 잡아야함
  • 프로미스의 에러는 catch하지 않아도 알아서 처리됨. 그래도 일단 붙여라
  • 예측불가능한 에러
    • process.on(‘uncaughtException’, (err) => { console.log(‘예기치못한 에러’, err); }); 이렇게 이벤트로 잡으면 됨. 이건 최후의 수단으로 사용함. 에러를 기록한 후
This post is licensed under CC BY 4.0 by the author.