IMCAT.DEV
로그인 가입
JavaScript 고급 프레임워크

JavaScript Node.js 기초

JavaScript Node.js 기초 — 고급

Node.js 기초

1. 도입 (왜 배워야 하는가)

Node.js는 JavaScript를 서버 측에서 실행할 수 있게 해주는 런타임 환경입니다. 현대 웹 애플리케이션의 대부분은 클라이언트와 서버 간의 비동기 통신을 요구하며, Node.js는 이러한 요구를 충족시키기 위해 설계되었습니다.

실무에서 Node.js를 사용할 경우, 다음과 같은 이점이 있습니다:

  • 비동기 처리: Node.js는 이벤트 기반이며, 비동기 I/O를 통해 높은 성능을 발휘합니다.
  • JavaScript 통일성: 프론트엔드와 백엔드 모두 JavaScript로 작성할 수 있어 개발자가 하나의 언어로 전체 애플리케이션을 관리할 수 있습니다.
  • 거대한 생태계: NPM(노드 패키지 매니저)을 통해 다양한 패키지를 쉽게 설치하고 사용할 수 있습니다.
  • Node.js를 모르면 고성능 서버를 구축하기 어렵고, 최신 웹 개발 트렌드에 뒤처질 수 있습니다. 또한, 다른 언어로 작성된 서버와의 통합이 복잡해질 수 있습니다.

    2. 핵심 개념 설명

    이벤트 루프 (Event Loop)

  • 정의: 이벤트 루프는 Node.js가 비동기 작업을 처리하는 방식입니다. 싱글 스레드로 작동하며, 비동기 작업이 완료되면 콜백을 호출합니다.
  • 비유: 주방에서 요리를 할 때, 요리사가 하나의 요리를 하면서 동시에 다른 재료를 준비하는 것과 같다고 생각할 수 있습니다.
  • 비동기 I/O (Asynchronous I/O)

  • 정의: 비동기 I/O는 작업을 요청한 후, 해당 작업이 완료될 때까지 기다리지 않고 다음 작업을 수행할 수 있게 해주는 방식입니다.
  • 비유: 친구에게 대화를 걸고, 답변이 오기 전에 다른 친구와 대화하는 것과 비슷합니다.
  • 관련 용어 정리

    용어설명
    콜백 (Callback)비동기 작업이 완료된 후 실행되는 함수
    프라미스 (Promise)비동기 작업의 결과를 나타내는 객체
    async/await비동기 코드를 더 읽기 쉽게 만들어주는 구문

    3. 기본 코드 예제

    Node.js의 기본적인 HTTP 서버를 만들어 보겠습니다.

    const http = require('http'); // http 모듈을 가져옵니다.
    
    const server = http.createServer((req, res) => { // 서버를 생성합니다.
        res.statusCode = 200; // 응답 상태 코드를 200으로 설정합니다.
        res.setHeader('Content-Type', 'text/plain'); // 응답 헤더에 Content-Type을 설정합니다.
        res.end('Hello, World!\n'); // 응답 본문을 설정하고 응답을 종료합니다.
    });
    
    const PORT = 3000; // 포트 번호를 설정합니다.
    server.listen(PORT, () => { // 서버를 해당 포트에서 대기하게 합니다.
        console.log(서버가 http://localhost:${PORT}에서 실행 중입니다.); // 서버 실행 메시지를 출력합니다.
    });

    실행 결과:

    서버가 http://localhost:3000에서 실행 중입니다.
  • 1행: http 모듈을 가져옵니다. 이 모듈은 HTTP 서버를 만들 때 필요합니다.
  • 3행: createServer 메서드를 사용해 서버를 생성합니다. 이 메서드는 요청이 들어올 때마다 호출되는 콜백 함수를 받습니다.
  • 4-6행: 응답 상태 코드와 헤더를 설정하고, 응답 본문을 작성한 후 응답을 종료합니다.
  • 8행: 서버가 대기할 포트를 설정합니다.
  • 9행: listen 메서드를 호출하여 서버를 시작하고, 시작 메시지를 콘솔에 출력합니다.
  • 4. 실전 활용 예제

    예제 1: 쇼핑몰에서 장바구니 기능 구현

    장바구니에 상품을 추가하는 API를 만들어 보겠습니다.

    const express = require('express'); // express 모듈을 가져옵니다.
    const app = express(); // express 애플리케이션을 생성합니다.
    app.use(express.json()); // JSON 형식의 요청 본문을 처리할 수 있게 합니다.
    
    let cart = []; // 장바구니를 저장할 배열입니다.
    
    app.post('/cart', (req, res) => { // POST 요청을 처리하는 엔드포인트를 생성합니다.
        const item = req.body; // 요청 본문에서 아이템을 가져옵니다.
        cart.push(item); // 장바구니에 아이템을 추가합니다.
        res.status(201).send('아이템이 장바구니에 추가되었습니다.'); // 성공 응답을 보냅니다.
    });
    
    const PORT = 3000;
    app.listen(PORT, () => {
        console.log(서버가 http://localhost:${PORT}에서 실행 중입니다.);
    });

    이 코드는 장바구니에 상품을 추가하는 기능을 제공합니다. 클라이언트에서 POST 요청을 보내면, 해당 상품이 장바구니 배열에 추가됩니다.

    예제 2: 사용자 인증 기능 구현

    사용자 로그인 기능을 추가해 보겠습니다.

    const express = require('express');
    const bodyParser = require('body-parser');
    const app = express();
    app.use(bodyParser.json());
    
    let users = { 'user1': 'password1' }; // 사용자 정보를 저장한 객체입니다.
    
    app.post('/login', (req, res) => {
        const { username, password } = req.body; // 요청 본문에서 사용자명과 비밀번호를 가져옵니다.
        if (users[username] && users[username] === password) { // 사용자 인증 확인
            res.status(200).send('로그인 성공!'); // 성공 응답
        } else {
            res.status(401).send('로그인 실패!'); // 실패 응답
        }
    });
    
    const PORT = 3000;
    app.listen(PORT, () => {
        console.log(서버가 http://localhost:${PORT}에서 실행 중입니다.);
    });

    이 코드는 사용자가 입력한 사용자명과 비밀번호를 확인하여 로그인 여부를 판단합니다.

    5. 흔한 실수와 주의사항

    실수 1: 비동기 코드를 동기처럼 처리하기

    const fs = require('fs');
    
    const data = fs.readFileSync('file.txt'); // 동기적으로 파일을 읽으려고 합니다.
    console.log(data); // 데이터가 없거나 에러가 발생할 수 있습니다.

    올바른 코드:

    const fs = require('fs');
    
    fs.readFile('file.txt', 'utf8', (err, data) => { // 비동기적으로 파일을 읽습니다.
        if (err) {
            console.error(err);
            return;
        }
        console.log(data); // 정상적으로 파일 내용을 출력합니다.
    });

    실수 2: 콜백 지옥

    doSomething(function(result) {
        doSomethingElse(result, function(newResult) {
            doThirdThing(newResult, function(finalResult) {
                console.log('결과:', finalResult);
            });
        });
    });

    올바른 코드 (Promise 사용):

    doSomething()
        .then(result => doSomethingElse(result))
        .then(newResult => doThirdThing(newResult))
        .then(finalResult => console.log('결과:', finalResult))
        .catch(err => console.error(err)); // 에러 처리

    6. 정리

  • Node.js는 비동기 I/O와 이벤트 루프를 통해 높은 성능을 제공합니다.
  • JavaScript를 서버 측에서 사용할 수 있게 해 줍니다.
  • Express와 같은 프레임워크를 통해 RESTful API 개발이 간편해집니다.
  • 비동기 코드를 사용할 때는 콜백, Promise, async/await 패턴을 이해하는 것이 중요합니다.
  • 다음에 학습하면 좋은 주제:

  • Express.js 심화
  • MongoDB와의 통합
  • WebSocket을 통한 실시간 통신 구현