본문으로 바로가기
제품데스크톱 도구TASTECAD도면 확인TASTEFILES파일 관리TASTEFTP파일 전송TASTESSH원격 작업공간TASTEZIP압축과 해제개발 도구TASTECODERust 통합 개발 환경TASTESTUDIO통합 개발·테스트 환경TASTEETL데이터 통합(ETL)서버TASTEREMOTE원격 데스크톱 서버TASTEGEO공간정보 서버TASTEMAIL메일 작업공간시작하기다운로드문서구매모든 제품
마켓플레이스
소식
개발소식오늘의 개발 소식개발 문서프로그래밍 언어RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron알고리즘알고리즘 기초알고리즘 핵심알고리즘 심화실무 알고리즘
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스커뮤니티 안내
협업기술 전수홈페이지 구축데스크톱 앱 구축릴리스·결제 파이프라인판매 파트너문의
서비스원격 데스크톱설치 패키지 커스텀
TASTEDEV
제품

데스크톱 도구

TASTECAD복잡한 도면을 가볍게 열다TASTEFILES필요한 파일만, 가장 빠르게TASTEFTP파일이 오가는 가장 단정한 길TASTESSH서버와 나 사이, 더 단단한 연결TASTEZIP더 빠르게 묶고, 더 안전하게 풀다

개발 도구

TASTECODERust 앱을 편집 · 빌드 · 디버깅 · 테스트까지 한 창에서TASTESTUDIO편집부터 원격 테스트와 승인 기반 AI 수정까지TASTEETL값을 보며 데이터를 옮깁니다

서버

TASTEREMOTE우리 회사 서버로 운영하는 원격 데스크톱TASTEGEOGeoServer 호환 공간정보 서버를 Rust로 다시 세웁니다TASTEMAIL메일의 주도권을 다시 내 손에

시작하기

다운로드모든 제품 최신 판문서제품 사용법구매구독 · 영구 라이선스모든 제품모든 제품 한눈에
모든 제품
마켓플레이스소식
개발

소식

오늘의 개발 소식언어 · 프레임워크 · GitHub · AI 공식 발표개발 문서언어 · 프레임워크 · 알고리즘 안내서

프로그래밍 언어

RustTypeScriptJavaScriptPythonGoC#JavaCC++KotlinDart

프레임워크

프런트엔드 프레임워크Next.jsReactVue.js · NuxtSvelteKitAngular
서버 프레임워크Spring BootDjangoFastAPIASP.NET CoreNestJS · Express
앱 · 데스크톱 프레임워크TauriFlutterReact NativeElectron

알고리즘

알고리즘 기초복잡도 분석 · 정렬 · 탐색 · 기본 자료구조 · 트리와 힙알고리즘 핵심그래프 탐색 · 최단 경로와 최소 신장 트리 · 동적 계획법 · 탐욕 알고리즘 · 분할 정복 · 백트래킹알고리즘 심화문자열 알고리즘 · 수학과 정수론 · 비트 연산 · 구간 트리 · 유니온 파인드실무 알고리즘코딩 면접 풀이 전략 · LRU 캐시 · 레이트 리미터 · 일관된 해시
개발 문서 전체 보기
커뮤니티
프로젝트빌더와 작업 발견개발 로그결정과 시행착오프롬프트재사용 가능한 지시AI 도구 이슈Claude · Codex · Gemini 문제와 우회법쇼케이스완성된 결과커뮤니티 안내공개하고 함께 만드는 방식
협업
기술 전수Rust·egui 네이티브 앱 만들기홈페이지 구축10개 언어, 계정, 문서·다운로드데스크톱 앱 구축Rust·egui, WebView 없이릴리스·결제 파이프라인서명 · MSI·deb·rpm·AppImage · 해시판매 파트너소개하고 결제액의 30% 받기문의구축 · 제휴 · 투자 문의
서비스
원격 데스크톱브라우저로 내 컴퓨터에 접속설치 패키지 커스텀필요한 기능만, 설정은 미리
구매
KO
한국어EnglishDeutschEspañolFrançaisItalianoPortuguês (Brasil)日本語简体中文繁體中文
로그인
로그인
TASTEDEV

작은 도구부터, 더 좋은 개발까지.

support@tastedev.netTASTEDEV 후원하기
제품제품군구매문서다운로드마켓플레이스고객 지원
커뮤니티프로젝트개발 로그프롬프트AI 도구 이슈쇼케이스
정책개인정보처리방침이용약관구독 약관환불 정책커뮤니티 운영 정책
계정로그인가입하기
방문자
오늘
012345678901234567890123456789012345678901234567890123456789
어제
012345678901234567890123456789012345678901234567890123456789
누적 조회
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
상호
지엑스소프트
대표자
최영구
사업자등록번호
853-44-00368
주소
인천광역시 미추홀구 경인로 351 9층 V24
전화
+82-10-4404-1523
이메일
whitecalvin@tastedev.net
개인정보 보호책임자
최영구

© 2026 TASTEDEV제품 정보는 현재 검증된 개발 소스를 기준으로 합니다.출시·고도화 중

JavaScript 문서
JavaScript
시작하기기본 문법타입과 데이터모듈과 패키지오류 처리와 테스트핵심 개념: 비동기와 클로저
토론

JavaScript 안내서 · 5/6

오류 처리와 테스트

프로그램은 언젠가 잘못된 입력, 끊긴 네트워크, 없는 파일을 만납니다. 이 장에서는 JavaScript에서 오류를 던지고 잡는 방법, 기본 오류 타입과 사용자 정의 오류, 비동기 코드의 오류 처리, 그리고 Node.js에 내장된 테스트 도구로 코드를 검증하는 방법을 다룹니다.

throw와 try...catch...finally

오류가 생기면 throw로 던지고, try...catch로 잡습니다. finally 블록은 오류가 났든 안 났든 항상 실행되므로 파일 닫기, 잠금 해제 같은 정리 작업에 씁니다. 문자열 대신 항상 Error 객체를 던지세요. 그래야 오류가 난 위치를 알려 주는 stack 정보가 함께 남습니다.

function parseAge(input) {
  const age = Number(input);
  if (!Number.isInteger(age) || age < 0) {
    throw new RangeError(`올바른 나이가 아닙니다: ${input}`);
  }
  return age;
}

try {
  console.log(parseAge("29"));  // 29
  console.log(parseAge("-3"));  // 여기서 오류가 던져집니다
  console.log("이 줄은 실행되지 않습니다");
} catch (error) {
  console.error(error.name, error.message); // RangeError 올바른 나이가 아닙니다: -3
} finally {
  console.log("검사 끝");
}

기본 오류 타입

JavaScript 엔진과 내장 함수는 상황에 따라 서로 다른 오류 타입을 던집니다. 모두 Error를 상속하므로 instanceof로 종류를 구분할 수 있습니다.

타입언제 발생하나
TypeErrorundefined의 속성을 읽거나 함수가 아닌 값을 호출할 때
ReferenceError선언하지 않은 변수를 쓸 때
RangeError허용 범위를 벗어난 값을 넘길 때(예: new Array(-1))
SyntaxError문법이 잘못되었거나 JSON.parse에 잘못된 문자열을 넘길 때

사용자 정의 오류와 cause

애플리케이션 고유의 오류는 Error를 상속한 클래스로 만들면 다루기 쉽습니다. 다른 오류를 감싸서 다시 던질 때는 두 번째 인수의 cause 옵션에 원래 오류를 넣으면 원인을 잃지 않습니다.

class NotFoundError extends Error {
  constructor(resource, options) {
    super(`${resource}을(를) 찾을 수 없습니다`, options);
    this.name = "NotFoundError";
    this.resource = resource;
  }
}

function loadConfig(text) {
  try {
    return JSON.parse(text);
  } catch (error) {
    throw new Error("설정 파일을 읽지 못했습니다", { cause: error });
  }
}

try {
  throw new NotFoundError("사용자 42");
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log("404 응답:", error.message);
  } else {
    throw error; // 처리할 수 없는 오류는 다시 던집니다
  }
}

try {
  loadConfig("{ 잘못된 JSON");
} catch (error) {
  console.log(error.message, "원인:", error.cause.name); // ... 원인: SyntaxError
}

모든 오류를 잡아서 조용히 삼키면 문제를 찾기 어려워집니다. 처리할 수 있는 오류만 잡고, 나머지는 다시 던지는 것이 원칙입니다.

비동기 코드의 오류

Promise가 실패(reject)하면 try...catch는 그 Promise를 await했을 때만 오류를 잡을 수 있습니다. await 없이 호출하면 오류가 catch를 지나쳐 버립니다. 처리되지 않은 Promise 거부는 Node.js에서 기본적으로 프로세스를 종료시키므로 반드시 처리해야 합니다.

import { readFile } from "node:fs/promises";

async function readJson(path) {
  try {
    const text = await readFile(path, "utf8");
    return JSON.parse(text);
  } catch (error) {
    if (error.code === "ENOENT") return null; // 파일이 없으면 null
    throw error;
  }
}

// then 체인에서는 .catch로 처리합니다
readJson("settings.json")
  .then((data) => console.log(data ?? "설정 없음"))
  .catch((error) => console.error("읽기 실패:", error));

// 여러 작업의 성공과 실패를 모두 확인하려면 allSettled
const results = await Promise.allSettled([readJson("a.json"), readJson("b.json")]);
for (const r of results) {
  console.log(r.status, r.status === "fulfilled" ? r.value : r.reason.message);
}

setTimeout 콜백 안에서 던진 오류는 바깥의 try...catch로 잡히지 않는다는 점도 기억하세요. 콜백은 나중에 별도로 실행되기 때문입니다. 이 동작은 6장의 이벤트 루프에서 자세히 설명합니다.

node:test로 테스트하기

Node.js에는 별도 설치 없이 쓸 수 있는 테스트 실행기 node:test와 검증 모듈 node:assert가 들어 있습니다. 테스트 파일 이름을 *.test.js처럼 지으면 node --test가 자동으로 찾아 실행합니다.

// age.test.js
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { parseAge } from "./age.js";

describe("parseAge", () => {
  it("숫자 문자열을 정수로 바꿉니다", () => {
    assert.equal(parseAge("29"), 29);
  });

  it("음수는 RangeError를 던집니다", () => {
    assert.throws(() => parseAge("-1"), RangeError);
  });

  it("비동기 함수의 실패도 검사할 수 있습니다", async () => {
    await assert.rejects(Promise.reject(new Error("실패")), /실패/);
  });

  it("객체는 내용을 깊게 비교합니다", () => {
    assert.deepEqual({ a: [1, 2] }, { a: [1, 2] });
  });
});
node --test
node --test --watch

다른 테스트 도구

더 많은 기능이 필요하면 커뮤니티 도구를 씁니다. Vitest는 Vite와 잘 맞고 실행이 빠르며, Jest는 오래 쓰여 자료가 많습니다. 두 도구 모두 describe, it(또는 test), expect를 중심으로 한 비슷한 문법을 씁니다.

// sum.test.js (Vitest)
import { describe, it, expect } from "vitest";
import sum from "./math.js";

describe("sum", () => {
  it("숫자를 모두 더합니다", () => {
    expect(sum(1, 2, 3)).toBe(6);
  });

  it("빈 인수는 0입니다", () => {
    expect(sum()).toBe(0);
  });
});

정리

  • 오류는 Error 객체로 던지고, 처리할 수 있는 곳에서만 try...catch로 잡습니다.
  • 정리 작업은 finally에, 감싼 오류의 원인은 cause에 담습니다.
  • 비동기 오류는 await와 try...catch 또는 .catch()로 반드시 처리합니다.
  • node:test와 node:assert/strict만으로도 충분한 테스트를 쓸 수 있고, 필요하면 Vitest나 Jest를 고릅니다.
이 장에 대해 질문이 있나요?
이전 장모듈과 패키지다음 장핵심 개념: 비동기와 클로저

댓글 0개

인기 댓글순최신순

로그인 · 로그인하면 댓글을 남길 수 있습니다.