Node.js의 모듈 시스템은 코드의 재사용성을 높이고, 코드의 관리와 유지보수를 용이하게 합니다. Node.js에서 모듈은 독립된 코드 조각으로, 필요한 곳에서 가져와 사용할 수 있습니다. Node.js 모듈 시스템의 기본적인 사용 방법과 예제를 통해 이해해봅시다.

 

모듈 시스템 이해

Node.js에서는 각 파일이 모듈로 간주됩니다. 모듈을 가져오거나 내보내기 위해 require와 module.exports 또는 exports를 사용합니다.

1. 내장 모듈 (Built-in Modules)

Node.js는 여러 유용한 내장 모듈을 제공합니다. 예를 들어, 파일 시스템 조작을 위한 fs, HTTP 서버 생성을 위한 http 모듈 등이 있습니다.

 

예제: 내장 모듈 사용

const fs = require('fs');

// 파일 읽기
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

 

2. 사용자 정의 모듈 (User-defined Modules)

사용자 정의 모듈을 만들어 코드의 재사용성을 높일 수 있습니다. 이를 위해 module.exports 또는 exports 객체를 사용합니다.

예제: 간단한 수학 모듈 만들기

  • math.js 파일 생성
// math.js
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

module.exports = {
  add,
  subtract
};

 

 

  • main.js 파일에서 모듈 사용
// main.js
const math = require('./math');

console.log(math.add(2, 3));       // 출력: 5
console.log(math.subtract(5, 2));  // 출력: 3

 

 

위 예제에서 math.js는 add와 subtract 함수를 내보내는 모듈입니다. main.js에서는 require 함수를 사용하여 math 모듈을 가져오고, 그 함수들을 사용할 수 있습니다.

 

3. 모듈의 module.exports와 exports

module.exports는 모듈에서 내보내는 객체를 설정합니다. exports는 module.exports의 별칭입니다. 둘의 차이점을 이해하는 것이 중요합니다.

예제: module.exports와 exports 비교

  • module1.js (module.exports 사용)
// module1.js
function greet(name) {
  return `Hello, ${name}!`;
}

module.exports = greet;

 

  • module2.js (exports 사용)
// module2.js
exports.greet = function(name) {
  return `Hi, ${name}!`;
};

 

  • main.js에서 두 모듈 사용
// main.js
const greet1 = require('./module1');
const greet2 = require('./module2').greet;

console.log(greet1('Alice'));  // 출력: Hello, Alice!
console.log(greet2('Bob'));    // 출력: Hi, Bob!

 

 

위 예제에서 module1.js는 module.exports를 사용하여 함수 자체를 내보냅니다. module2.js는 exports를 사용하여 객체의 프로퍼티로 함수를 내보냅니다.

 

요약

  • 내장 모듈 사용: Node.js가 제공하는 기본 모듈들을 사용하여 파일 시스템, HTTP 등 다양한 기능을 활용할 수 있습니다.
  • 사용자 정의 모듈 작성 및 사용: 필요한 기능을 모듈로 작성하여 다른 파일에서 require로 가져와 사용할 수 있습니다.
  • module.exports와 exports: 모듈에서 내보낼 때 module.exports와 exports의 차이를 이해하고 적절히 사용합니다.

Node.js의 모듈 시스템을 이해하고 사용하는 것은 더 큰 애플리케이션을 구축할 때 매우 유용합니다.

 

Node.js와 npm(Node Package Manager)의 설치 및 환경 설정

Node.js와 npm은 JavaScript 개발을 위해 중요한 도구입니다. Node.js는 JavaScript를 서버 측에서 실행할 수 있는 런타임 환경이며, npm은 Node.js 패키지 매니저로, 다양한 라이브러리와 도구를 쉽게 설치하고 관리할 수 있게 해줍니다. 초보자를 위한 설치 및 환경 설정 과정을 자세히 설명하겠습니다.

1. Node.js와 npm 설치

Step 1: Node.js 웹사이트 방문

먼저, Node.js 공식 웹사이트에 방문합니다. 이 웹사이트에서 최신 안정 버전(LTS)을 다운로드합니다. LTS 버전은 장기 지원 버전으로, 안정성과 호환성이 보장됩니다.

 

Step 2: 설치 파일 다운로드

웹사이트에서 운영 체제에 맞는 설치 파일을 다운로드합니다. Node.js는 Windows, macOS, Linux 등 다양한 운영 체제를 지원합니다.

 

Step 3: 설치 파일 실행

다운로드한 설치 파일을 실행합니다. 설치 과정은 일반적인 소프트웨어 설치와 비슷합니다.

  1. Windows: 설치 마법사를 따라 Next 버튼을 클릭하고, 라이센스 동의 후 Install 버튼을 클릭하여 설치를 완료합니다.
  2. macOS: 다운로드한 패키지 파일을 열고, 설치 마법사를 따라 진행합니다.
  3. Linux: 배포판에 따라 다르지만, 보통 다음 명령어를 터미널에 입력하여 설치할 수 있습니다.
sudo apt-get update
sudo apt-get install nodejs
sudo apt-get install npm

 

Step 4: 설치 확인

설치가 완료되면, 터미널(또는 명령 프롬프트)을 열고 다음 명령어를 입력하여 Node.js와 npm이 올바르게 설치되었는지 확인합니다.

node -v
npm -v

 

이 명령어들은 각각 Node.js와 npm의 버전을 출력합니다. 버전 번호가 출력되면 설치가 성공적으로 완료된 것입니다.

 

2. Node.js 기본 개념

Node.js란?

Node.js는 Chrome의 V8 JavaScript 엔진을 기반으로 한 JavaScript 런타임입니다. Node.js를 사용하면 브라우저가 아닌 서버 측에서도 JavaScript를 실행할 수 있습니다. 주요 특징으로는 비동기 이벤트 기반 모델과 높은 성능이 있습니다.

Node.js의 특징

  • 비동기 I/O: Node.js는 비동기식 입력/출력(I/O) 작업을 처리하여 높은 처리량과 성능을 자랑합니다. 이는 파일 읽기/쓰기, 네트워크 요청 등의 작업에서 중요합니다.
  • 이벤트 기반: Node.js는 이벤트 루프를 사용하여 이벤트 기반의 비동기 프로그래밍을 쉽게 구현할 수 있습니다.
  • 싱글 스레드: Node.js는 싱글 스레드 이벤트 루프 모델을 사용합니다. 이는 메모리 사용을 줄이고, 동시성을 유지하면서도 높은 성능을 제공합니다.

3. 간단한 Node.js 애플리케이션 작성

Node.js를 설치한 후, 간단한 "Hello, World!" 애플리케이션을 작성하여 Node.js의 기본 사용법을 익혀봅시다.

 

예제: "Hello, World!" 서버

  • 파일 생성: 프로젝트 폴더를 만들고, 그 안에 app.js 파일을 생성합니다.
mkdir my-first-node-app
cd my-first-node-app
touch app.js

 

  • 코드 작성: app.js 파일을 열고, 다음 코드를 작성합니다.
const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!\n');
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

 

  • 서버 실행: 터미널에서 다음 명령어를 입력하여 서버를 실행합니다.
node app.js

 

 

이 명령어를 실행하면 "Server running at http://127.0.0.1:3000/" 메시지가 출력됩니다. 웹 브라우저를 열고 http://127.0.0.1:3000/에 접속하면 "Hello, World!" 메시지를 볼 수 있습니다.

 

VS Code에서 Node.js 환경 설정 및 예제 실행

1. VS Code 설치

VS Code가 설치되어 있지 않다면, VS Code 공식 웹사이트에서 다운로드하여 설치합니다.

 

2. Node.js 설치 확인

Node.js와 npm이 설치되어 있는지 확인합니다. 터미널을 열고 다음 명령어를 입력하여 설치를 확인합니다.

node -v
npm -v

 

이 명령어들은 각각 Node.js와 npm의 버전을 출력합니다. 버전 번호가 출력되면 Node.js와 npm이 올바르게 설치된 것입니다.

3. VS Code에서 프로젝트 폴더 열기

  1. VS Code를 실행합니다.
  2. 파일 -> 열기를 선택하고, 프로젝트 폴더(예: my-first-node-app)를 선택합니다.
  3. VS Code에서 프로젝트 폴더가 열리면, 왼쪽 사이드바에서 폴더 구조를 확인할 수 있습니다.

4. 프로젝트 폴더 구조 설정

  1. 프로젝트 폴더 안에 app.js 파일을 생성합니다.
  2. app.js 파일에 다음 코드를 작성합니다
const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!\n');
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

 

5. 터미널 열기

VS Code에서 통합 터미널을 열어 프로젝트를 실행할 수 있습니다.

  1. 보기 -> 터미널을 선택하여 통합 터미널을 엽니다.
  2. 통합 터미널이 열리면, 현재 디렉토리가 프로젝트 폴더(my-first-node-app)인지 확인합니다.

6. 서버 실행

통합 터미널에서 다음 명령어를 입력하여 Node.js 서버를 실행합니다.

node app.js

 

이 명령어를 실행하면 "Server running at http://127.0.0.1:3000/" 메시지가 출력됩니다. 이는 서버가 성공적으로 실행되었음을 의미합니다.

7. 웹 브라우저에서 확인

웹 브라우저를 열고, 주소 표시줄에 http://127.0.0.1:3000/를 입력합니다. 그러면 "Hello, World!" 메시지가 브라우저에 표시됩니다.

VS Code에서 Node.js 디버깅

VS Code는 강력한 디버깅 기능을 제공합니다. Node.js 애플리케이션을 디버깅하는 방법을 알아보겠습니다.

  1. 디버깅 구성 설정
    • VS Code에서 왼쪽 사이드바의 디버그 아이콘을 클릭합니다.
    • 실행 및 디버그 패널에서 디버그 구성 생성을 클릭합니다.
    • 팝업 메뉴에서 Node.js를 선택합니다.
    • 그러면 launch.json 파일이 생성되고 기본 설정이 추가됩니다.
  2. 브레이크포인트 설정
    • app.js 파일에서 디버깅하고자 하는 줄 번호를 클릭하여 브레이크포인트를 설정합니다. 예를 들어, res.end('Hello, World!\n'); 줄에 브레이크포인트를 설정할 수 있습니다.
  3. 디버깅 시작
    • 디버그 패널에서 디버그 시작 버튼을 클릭합니다.
    • 디버그 콘솔에 디버깅 정보가 표시되며, 브레이크포인트에서 코드 실행이 중지됩니다.
    • 변수 값을 확인하고, 코드의 흐름을 따라가며 디버깅할 수 있습니다.

이렇게 하면 VS Code에서 Node.js 환경을 설정하고, 간단한 서버를 구현하고, 실행 및 디버깅할 수 있습니다. VS Code의 편리한 기능을 활용하여 Node.js 개발을 더욱 효율적으로 할 수 있습니다.

 

 

Node.js

 

Node.js를 5주 동안 학습하는 커리큘럼을 구성했습니다. 이 커리큘럼은 주차별로 학습 목표와 주요 학습 내용을 포함하며, 실습 예제를 통해 학습을 강화합니다.

 

1주차: Node.js 기본 개념 및 환경 설정

목표

  • Node.js와 npm(Node Package Manager)의 설치 및 환경 설정
  • Node.js의 기본 개념과 특징 이해
  • 간단한 Node.js 애플리케이션 작성

학습 내용

  • Node.js 설치 및 설정
    • Node.js와 npm 설치
    • 설치 확인 (node -v, npm -v)
    • Node.js REPL (Read-Eval-Print Loop) 사용해보기
  • Node.js 기본 개념
    • Node.js의 이벤트 기반 비동기 I/O 모델 이해
    • Node.js의 장점과 특징
    • 기본 모듈 시스템 (CommonJS)
  • 첫 번째 Node.js 애플리케이션
    • 간단한 "Hello, World!" 서버 작성
const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!\n');
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at http://127.0.0.1:3000/');
});

 

2주차: Node.js 모듈 시스템과 파일 시스템

목표

  • Node.js의 모듈 시스템 이해
  • 파일 시스템 모듈 사용법 익히기
  • 비동기 파일 읽기/쓰기 작업 수행

학습 내용

  • Node.js 모듈 시스템
    • 모듈 정의 및 사용 (exports, require)
    • 내장 모듈 사용 (예: path, os)
    • 사용자 정의 모듈 작성 및 사용
  • 파일 시스템 (fs) 모듈
    • 동기 및 비동기 파일 읽기/쓰기
    • 파일 시스템 조작 (파일 삭제, 디렉터리 생성 등)
const fs = require('fs');

// 비동기 파일 읽기
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

// 비동기 파일 쓰기
fs.writeFile('example.txt', 'Hello, Node.js!', (err) => {
  if (err) throw err;
  console.log('File has been saved!');
});

 

3주차: HTTP 모듈과 Express.js 기본

목표

  • HTTP 모듈을 사용한 간단한 웹 서버 구축
  • Express.js 프레임워크를 사용한 웹 애플리케이션 구축

학습 내용

  • HTTP 모듈
    • HTTP 요청 및 응답 처리
    • URL과 쿼리 문자열 파싱
    • 간단한 라우팅 구현
  • Express.js 기본
    • Express.js 설치 및 설정
    • 기본 라우팅 및 미들웨어 이해
    • 정적 파일 제공
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, World!');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});

 

4주차: 데이터베이스 연결 및 RESTful API

목표

  • MongoDB와 같은 NoSQL 데이터베이스 사용법 익히기
  • Mongoose를 사용한 데이터베이스 연결 및 스키마 정의
  • RESTful API 구축 및 테스트

학습 내용

  • MongoDB와 Mongoose
    • MongoDB 설치 및 기본 명령어 사용
    • Mongoose 설치 및 설정
    • 스키마와 모델 정의
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true, useUnifiedTopology: true });

const userSchema = new mongoose.Schema({
  name: String,
  age: Number
});

const User = mongoose.model('User', userSchema);

 

  • RESTful API 구축
    • CRUD(Create, Read, Update, Delete) 기능 구현
    • API 엔드포인트 정의 및 테스트
app.get('/users', async (req, res) => {
  const users = await User.find();
  res.json(users);
});

app.post('/users', async (req, res) => {
  const newUser = new User(req.body);
  await newUser.save();
  res.status(201).send(newUser);
});

 

5주차: 비동기 처리와 배포

목표

  • 비동기 처리 심화 학습 (Promise, async/await)
  • 애플리케이션 배포 이해 및 실습

학습 내용

  • 비동기 처리 심화
    • Promise와 async/await을 사용한 비동기 코드 작성
    • 에러 처리 및 디버깅
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

fetchData();

 

  • 애플리케이션 배포
    • Heroku, Vercel 등의 플랫폼을 사용한 배포
    • 배포 시 고려사항 (환경 변수, 보안, 스케일링)
    • 간단한 배포 실습
# Heroku 배포 예제
heroku create my-node-app
git push heroku main
heroku open

 

이 커리큘럼을 통해 Node.js의 기본 개념부터 시작해 실용적인 애플리케이션 구축 및 배포까지 단계별로 학습할 수 있습니다. 각 주차의 학습 내용을 철저히 이해하고 실습해보세요.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

async 함수와 await 키워드 이해하기

 

async 함수와 await 키워드는 JavaScript에서 비동기 코드를 더 읽기 쉽고, 동기 코드처럼 작성할 수 있게 해주는 기능입니다. 이들은 Promise를 사용하는 것보다 코드를 더 간결하게 만들고, 콜백 지옥을 더욱 효과적으로 피할 수 있게 합니다.

 

async 함수

 

async 키워드를 함수 앞에 붙이면 해당 함수는 항상 Promise를 반환합니다. 함수 내부에서 return 값은 자동으로 Promise.resolve()로 감싸집니다.

 

await 키워드

 

await 키워드는 async 함수 안에서만 사용할 수 있으며, Promise가 이행될 때까지 함수 실행을 일시 정지시킵니다. Promise가 이행되면 await은 Promise의 결과 값을 반환합니다. 이는 동기 함수가 값을 반환하는 것과 비슷하게 동작합니다.

 

async 함수 정의 및 사용

async function fetchData() {
  return "Data fetched";
}

fetchData().then(data => console.log(data));  // 출력: Data fetched

 

이 예제에서 fetchData 함수는 async 키워드를 사용하여 정의되었습니다. 이 함수는 "Data fetched" 문자열을 반환하며, 이는 자동으로 Promise.resolve()로 감싸져 반환됩니다.

 

await 키워드를 사용한 비동기 작업

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function run() {
  console.log("Start");
  await delay(2000);  // 2초 대기
  console.log("End");
}

run();

 

이 예제에서는 delay 함수가 Promise를 반환하여, 지정된 시간(ms) 후에 이행됩니다. run 함수는 async 함수로 정의되어 있으며, await 키워드를 사용하여 delay 함수가 완료될 때까지 대기합니다.

 

실제 API 호출 예제

 

async와 await를 사용하여 실제 API 호출을 더 간단하게 처리할 수 있습니다.

async function fetchUserData(userId) {
  try {
    const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error fetching user data:', error);
  }
}

async function displayUserData(userId) {
  const userData = await fetchUserData(userId);
  if (userData) {
    console.log(`Name: ${userData.name}`);
    console.log(`Email: ${userData.email}`);
  }
}

displayUserData(1);

 

이 예제에서는 fetchUserData 함수가 특정 사용자의 데이터를 API로부터 가져옵니다. await 키워드는 fetch와 response.json() 호출에 사용되어, 비동기적으로 데이터를 가져오고 파싱합니다. displayUserData 함수는 fetchUserData 함수를 호출하고, 가져온 사용자 데이터를 콘솔에 출력합니다.

 

예제 설명

  • 간단한 비동기 함수: async 키워드로 정의된 함수는 항상 Promise를 반환합니다. 따라서 반환된 값을 then()을 통해 처리할 수 있습니다.
  • 비동기 작업 대기: await 키워드를 사용하여 Promise가 해결될 때까지 대기합니다. 이는 then()을 사용하는 것보다 코드가 더 간결하고 읽기 쉽게 만듭니다.
  • API 호출과 에러 처리: try...catch 블록을 사용하여 비동기 함수 내에서 발생할 수 있는 오류를 처리할 수 있습니다. 이는 비동기 작업을 수행할 때 중요한 부분입니다.

이제 async 함수와 await 키워드를 사용하여 비동기 코드를 더욱 간단하고 명료하게 작성할 수 있게 되었습니다. 이를 통해 비동기 작업을 동기 코드처럼 쉽게 다룰 수 있으며, 코드의 가독성과 유지 보수성을 높일 수 있습니다.

 

Promise 이해하기

Promise는 JavaScript에서 비동기 연산의 최종 완료(또는 실패) 및 그 결과값을 나타내는 객체입니다. 비동기 작업을 더 쉽고 효율적으로 관리할 수 있게 해 주며, 콜백 지옥(callback hell)을 피하는 데 유용합니다.

 

Promise의 기본 구조

Promise 객체는 비동기 작업을 수행하고, 그 작업이 성공적으로 완료되었을 때와 실패했을 때의 처리 로직을 담고 있습니다.

 

기본 구조

const myPromise = new Promise((resolve, reject) => {
  // 비동기 작업을 여기에 구현
  if (/* 작업 성공 */) {
    resolve(value);  // 성공 결과를 반환
  } else {
    reject(error);  // 실패 이유를 반환
  }
});
  • resolve: 비동기 작업이 성공적으로 완료되었을 때 호출됩니다. 이 함수를 호출하며 비동기 작업의 결과를 전달할 수 있습니다.
  • reject: 비동기 작업이 실패했을 때 호출됩니다. 실패의 이유(에러)를 전달합니다.

예제 1: 간단한 Promise 생성과 사용

const checkNumber = new Promise((resolve, reject) => {
  const number = Math.floor(Math.random() * 100);
  setTimeout(() => {
    if (number % 2 === 0) {
      resolve(`Even number: ${number}`);
    } else {
      reject(`Odd number: ${number}`);
    }
  }, 2000);
});

checkNumber.then(message => {
  console.log("Success:", message);
}).catch(error => {
  console.error("Error:", error);
});

 

이 예제에서 checkNumber는 0에서 99까지의 무작위 수를 생성하고, 그 수가 짝수이면 성공 메시지를, 홀수이면 오류 메시지를 반환합니다. .then()과 .catch() 메서드를 사용하여 각각 성공과 실패 시의 로직을 처리합니다.

 

예제 2: Promise 체이닝

 

Promise는 .then()을 사용하여 여러 비동기 작업을 순차적으로 연결할 수 있습니다. 각 .then() 메서드는 새로운 Promise를 반환합니다.

function doubleNumber(num) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(num * 2), 1000);
  });
}

doubleNumber(5)
  .then(result => {
    console.log(result);  // 10
    return doubleNumber(result);  // 결과를 다시 두 배로
  })
  .then(result => {
    console.log(result);  // 20
    return doubleNumber(result);
  })
  .then(result => {
    console.log(result);  // 40
  });

 

이 예제에서는 숫자를 받아 1초 후에 그 수를 두 배로 증가시키는 doubleNumber 함수를 정의했습니다. 이 함수는 Promise를 반환하며, 이를 통해 연속적으로 숫자를 두 배로 증가시키는 작업을 수행합니다.

 

예제 설명

 

위 예제들은 Promise의 기본적인 사용 방법을 보여줍니다. Promise를 사용함으로써 비동기 작업을 보다 세련되게 관리할 수 있으며, 코드의 가독성과 유지 보수성이 향상됩니다. 다음 강의에서는 Promise를 활용한 더 복잡한 시나리오와 async/await 구문을 배울 예정입니다.

 

왜 Promise가 콜백 지옥(callback hell)을 피하는 데 유용한가?

Promise가 콜백 지옥을 피하는 데 유용한 이유는 주로 그 구조와 특성 때문입니다. 콜백 지옥은 복잡한 비동기 JavaScript 코드에서 흔히 발생하는 문제로, 여러 콜백 함수가 중첩되고, 그로 인해 코드의 가독성과 유지 보수성이 현저히 저하되는 현상을 말합니다. 이 문제를 Promise를 통해 해결할 수 있는 이유는 다음과 같습니다.

 

1. 플랫한 코드 구조

Promise는 중첩된 콜백 함수 대신 연쇄적인 .then() 메소드를 사용하여 결과를 처리합니다. 각 .then()은 비동기 연산의 결과를 기다리는 대기열과 같은 역할을 하며, 이전 연산의 결과를 다음 연산으로 전달합니다. 이로 인해 코드가 수평적으로 확장되어 가독성이 크게 향상됩니다.

 

예제: 콜백 지옥

getData(function(a){
    getMoreData(a, function(b){
        getMoreData(b, function(c){ 
            getMoreData(c, function(d){ 
                getMoreData(d, function(e){ 
                    // 콜백 지옥
                });
            });
        });
    });
});

 

예제: Promise 사용

getData()
  .then(a => getMoreData(a))
  .then(b => getMoreData(b))
  .then(c => getMoreData(c))
  .then(d => getMoreData(d))
  .then(e => {
    // 더 깔끔하고 가독성이 좋음
  });

 

2. 오류 처리의 단순화

콜백 지옥에서는 각 콜백 함수마다 개별적으로 오류를 처리해야 하기 때문에 오류 처리 코드가 복잡해집니다. 반면, Promise는 .catch() 메소드를 사용하여 연쇄된 모든 비동기 연산에서 발생할 수 있는 오류를 한 곳에서 처리할 수 있게 합니다. 이는 오류 처리 로직을 중앙화하여 코드를 더욱 깔끔하게 만들어 줍니다.

getData()
  .then(a => getMoreData(a))
  .then(b => getMoreData(b))
  .catch(error => {
    // 모든 단계에서 발생할 수 있는 예외 처리
    console.error(error);
  });

 

3. 상태 관리

Promise 객체는 세 가지 상태를 가집니다: 대기(pending), 이행(fulfilled), 거부(rejected). 이 상태들은 Promise의 수명 동안 한 번만 변경될 수 있으며, 상태에 따라 적절한 처리가 자동으로 이루어집니다. 이는 비동기 작업의 상태를 명확하게 관리할 수 있게 해 주며, 불필요한 조건문을 줄여줍니다.

 

이러한 이유들로 Promise는 복잡한 비동기 코드를 보다 체계적이고 관리하기 쉽게 만들어 주며, 콜백 지옥에서 발생하는 문제들을 효과적으로 해결할 수 있는 강력한 도구입니다.

비동기 처리의 이해

비동기 처리는 특정 코드의 실행 완료를 기다리지 않고 다음 코드를 바로 실행하는 JavaScript의 처리 방식입니다. setTimeout과 setInterval은 JavaScript에서 비동기적으로 시간 지연과 반복 작업을 처리할 수 있는 두 가지 기본적인 함수입니다.

setTimeout

setTimeout 함수는 지정된 시간이 지난 후에 함수를 한 번 실행합니다. 이 함수는 비동기 작업에 유용하게 사용됩니다.

 

기본 구조

setTimeout(function, delay);
  • function: 지연 후 실행할 함수
  • delay: 밀리초 단위의 지연 시간 (1000 밀리초 = 1초)

예제 1: 간단한 메시지 출력

setTimeout(function() {
  console.log("This message is shown after 3 seconds.");
}, 3000);

 

이 예제에서는 3000 밀리초(3초) 후에 콘솔에 메시지를 출력합니다.

 

setInterval

setInterval 함수는 지정된 시간 간격마다 함수를 반복적으로 실행합니다. 이 함수는 주기적인 업데이트가 필요할 때 사용됩니다.

 

기본 구조

setInterval(function, interval);
  • function: 주기적으로 실행할 함수
  • interval: 실행 간격을 나타내는 밀리초 단위의 시간

예제 2: 주기적인 시간 출력

setInterval(function() {
  console.log("Current time: " + new Date().toLocaleTimeString());
}, 1000);

 

이 예제에서는 매초마다 현재 시간을 콘솔에 출력합니다.

 

예제 3: 타이머 구현

setTimeout과 setInterval을 사용하여 간단한 타이머를 구현할 수 있습니다. 사용자가 지정한 시간 후에 알림을 주는 타이머를 만들어보겠습니다.

function startTimer(duration) {
  let remaining = duration;
  const timerInterval = setInterval(function() {
    remaining--;
    console.log(remaining + " seconds remaining");
    if (remaining <= 0) {
      clearInterval(timerInterval);
      console.log("Timer is done!");
    }
  }, 1000);
}

startTimer(5);  // 5초간 동작하는 타이머

 

이 코드는 startTimer 함수를 정의하여, 호출할 때 지정된 시간(초 단위) 동안 매초마다 남은 시간을 출력하고, 시간이 끝나면 "Timer is done!"을 출력하고 타이머를 중지합니다.

 

위 예제들에서 setTimeout과 setInterval은 JavaScript에서의 비동기 처리 방법을 보여줍니다. 이들 함수를 통해 시간에 따라 코드 실행을 제어할 수 있으며, 사용자 인터페이스를 동적으로 만들거나, 데이터를 주기적으로 업데이트하는 등 다양한 상황에서 유용하게 사용됩니다.

 

이번 주 강의에서 배운 setTimeout과 setInterval을 통해 간단하게 시간 기반의 작업을 스케줄링하는 방법을 이해하고 적용할 수 있게 되었습니다. 다음 강의에서는 JavaScript의 Promise와 async/await를 이용한 더 고급 비동기 처리 방법을 배울 예정입니다.

 

 

 

 

 

 

 

이벤트 리스너는 사용자의 행동(클릭, 스크롤, 키보드 입력 등)을 감지하고 이에 반응하여 특정 동작을 수행하도록 설정하는 JavaScript의 기능입니다. 이벤트 핸들링은 웹 페이지를 대화형으로 만드는 데 필수적입니다.

 

이벤트 리스너의 추가

이벤트 리스너를 추가하는 기본적인 방법은 addEventListener() 메소드를 사용하는 것입니다. 이 메소드는 두 가지 주요 매개변수를 받습니다: 이벤트의 종류와 이벤트가 발생했을 때 실행될 콜백 함수.

 

기본 구조

element.addEventListener(eventType, eventHandler);

 

  • eventType: 감지하려는 이벤트의 유형 (예: "click", "mouseover", "keyup" 등)
  • eventHandler: 이벤트 발생 시 실행될 함수

예제 1: 클릭 이벤트 리스너 추가

<button id="clickMeButton">Click Me!</button>

<script>
  const button = document.getElementById('clickMeButton');
  button.addEventListener('click', function() {
    alert('Button was clicked!');
  });
</script>

 

이 예제에서는 버튼을 클릭할 때마다 경고창이 나타나도록 설정하였습니다. addEventListener를 사용하여 click 이벤트에 대한 리스너를 버튼에 추가하고, 클릭 시 사용자에게 알림을 제공합니다.

 

예제 2: 마우스 오버 이벤트 리스너 추가

<div id="hoverDiv" style="width: 200px; height: 200px; background-color: #00D;">Hover over me!</div>

<script>
  const hoverDiv = document.getElementById('hoverDiv');
  hoverDiv.addEventListener('mouseover', function() {
    this.style.backgroundColor = '#D00';
  });
  hoverDiv.addEventListener('mouseout', function() {
    this.style.backgroundColor = '#00D';
  });
</script>

 

이 예제에서는 사용자가 div 요소 위로 마우스를 올리면 배경색이 변경됩니다. mouseover 이벤트가 div의 배경색을 빨간색으로 변경하고, mouseout 이벤트가 원래의 색으로 복원합니다.

 

이벤트 객체의 활용

이벤트 핸들러 함수에는 이벤트와 관련된 정보를 담고 있는 이벤트 객체가 자동으로 전달됩니다. 이 객체를 사용하여, 예를 들어 어느 키가 눌렸는지, 어느 요소가 클릭되었는지 등의 정보를 얻을 수 있습니다.

 

예제 3: 키보드 이벤트와 이벤트 객체

<input type="text" id="inputBox" placeholder="Type something...">

<script>
  const inputBox = document.getElementById('inputBox');
  inputBox.addEventListener('keyup', function(event) {
    console.log(`Key pressed: ${event.key}`);
  });
</script>

 

이 예제에서는 사용자가 입력 필드에 텍스트를 입력할 때마다 어떤 키가 눌렸는지 콘솔에 출력합니다. keyup 이벤트는 키보드의 키가 눌렸다가 떼어질 때 발생하며, 이벤트 객체의 key 속성을 통해 어떤 키가 눌렸는지 확인할 수 있습니다.

이벤트 리스너와 이벤트 핸들링을 통해 웹 페이지를 더욱 동적이고 상호작용적으로 만들 수 있습니다. 사용자 경험을 향상시키는 이 기능들을 활용해보세요.

 

 

 

웹 페이지의 동적인 행동을 구현하려면, 문서의 요소들을 선택, 생성 및 수정하는 방법을 알아야 합니다. 이 과정에서 DOM (Document Object Model)은 중심적인 역할을 하며, JavaScript를 통해 이러한 조작을 쉽게 할 수 있습니다.

 

요소 선택하기

웹 페이지에서 요소를 선택하는 것은 DOM 조작의 시작점입니다. 앞서 언급한 메소드 외에도 다양한 방법으로 요소를 선택할 수 있습니다.

 

예제: querySelector와 querySelectorAll

 

CSS 선택자를 활용하여 요소를 선택할 수 있습니다. 이 방법은 매우 강력하며 유연합니다.

<div id="content">
  <p class="message">Hello, this is a message.</p>
  <p class="message">Hello, this is another message.</p>
</div>

<script>
  // 첫 번째 <p> 태그 선택
  const firstMessage = document.querySelector('#content .message');
  console.log(firstMessage.textContent);  // "Hello, this is a message."

  // 모든 <p> 태그 선택
  const allMessages = document.querySelectorAll('#content .message');
  allMessages.forEach(message => {
    console.log(message.textContent);
  });
</script>

 

요소 생성하기

새로운 요소를 생성하는 것은 웹 페이지에 동적으로 내용을 추가할 때 필수적입니다.

예제: 요소 생성 및 추가

 

<div id="container"></div>

<script>
  // 새로운 <p> 요소 생성
  const newParagraph = document.createElement('p');
  newParagraph.textContent = 'This is a new paragraph.';

  // 생성된 <p> 요소를 #container div에 추가
  const container = document.getElementById('container');
  container.appendChild(newParagraph);
</script>

 

요소 수정하기

선택한 요소의 내용을 변경하거나 스타일을 수정할 수 있습니다.

 

예제: 요소 내용 및 스타일 변경

<p id="greeting">Hello, World!</p>

<script>
  const greeting = document.getElementById('greeting');
  // 텍스트 변경
  greeting.textContent = 'Updated Hello, World!';

  // 스타일 변경
  greeting.style.color = 'blue';
  greeting.style.fontSize = '20px';
</script>

 

요소의 속성과 이벤트 처리

요소의 속성을 설정하거나 변경하고, 이벤트 리스너를 추가하여 사용자의 동작에 반응할 수 있습니다.

 

예제: 속성 설정 및 이벤트 리스너 추가

<a href="#" id="myLink">Visit Google</a>

<script>
  const myLink = document.getElementById('myLink');
  
  // 속성 변경
  myLink.setAttribute('href', 'https://www.google.com');

  // 클릭 이벤트 리스너 추가
  myLink.addEventListener('click', function(event) {
    event.preventDefault();  // 기본 동작 방지
    console.log('Link clicked!');
    window.location.href = this.getAttribute('href');
  });
</script>
window.location.href = this.getAttribute('href');

 

이 코드는 현재 브라우저 창의 위치(URL)을 변경하는 작업을 수행합니다. 여기서 사용된 JavaScript 명령어들을 하나씩 살펴보면:

  1. window.location.href: window 객체는 브라우저 창을 나타냅니다. location 객체는 현재 페이지의 주소(URL)와 관련된 다양한 정보와 메서드를 포함하고 있습니다. href 속성은 해당 위치 객체의 URL을 문자열로 나타냅니다. 이 속성에 새로운 URL을 할당하면, 브라우저는 할당된 URL로 페이지를 리다이렉트(재이동)합니다.
  2. this.getAttribute('href'): this 키워드는 이벤트가 발생한 요소, 이 경우 <a> 태그를 참조합니다. getAttribute('href') 메서드는 요소의 href 속성 값, 즉 <a> 태그의 href 속성에 설정된 URL을 문자열로 반환합니다. 예를 들어, Visit Google에서 this.getAttribute('href')는 "https://www.google.com"을 반환합니다.

따라서 window.location.href = this.getAttribute('href'); 라인은 클릭된 링크(<a> 태그)의 href 속성 값으로 페이지를 리다이렉트합니다. 이는 JavaScript를 사용하여 기본 링크 동작을 향상시키거나 수정하기 위해 사용됩니다. 특히, 이벤트 리스너 내에서 추가적인 로직을 실행한 후 페이지를 이동시킬 때 유용합니다. 예를 들어, 사용자의 행동을 로깅하거나 확인 메시지를 표시한 후에 페이지를 이동시킬 수 있습니다.

 

이렇게 요소를 선택, 생성, 수정하는 기본적인 DOM 조작 방법을 통해 웹 페이지의 구조와 내용을 동적으로 제어할 수 있습니다. 이를 활용하면, 사용자의 상호작용에 따라 페이지를 실시간으로 업데이트하거나 변형시킬 수 있어 웹 애플리케이션의 가능성이 크게 확장됩니다. 다음 강의에서는 이벤트 처리에 대해 더 깊이 다룰 예정입니다.

 

+ Recent posts