ν‹°μŠ€ν† λ¦¬ λ·°

μ—λŸ¬ 처리의 ν•„μš”μ„±

μ—λŸ¬κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 것은 λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ, μ΄λŸ¬ν•œ μ—λŸ¬λ‚˜ μ˜ˆμ™Έμ μΈ 상황에 λŒ€μ‘ν•˜μ§€ μ•ŠμœΌλ©΄ ν”„λ‘œκ·Έλž¨μ€ κ°•μ œ μ’…λ£Œλ  κ²ƒμž…λ‹ˆλ‹€.

 

μ—λŸ¬λ‚˜ μ˜ˆμ™Έμ μΈ 상황은 μ•„λž˜μ™€ 같이 λ‹€μ–‘ν•©λ‹ˆλ‹€.

 

// μ—λŸ¬1
console.log('[Start]');

foo(); // ReferenceError: foo is not defined
// λ°œμƒν•œ μ—λŸ¬λ₯Ό λ°©μΉ˜ν•˜λ©΄ ν”„λ‘œκ·Έλž¨μ€ κ°•μ œ μ’…λ£Œλœλ‹€.

// μ—λŸ¬μ— μ˜ν•΄ ν”„λ‘œκ·Έλž¨μ΄ κ°•μ œ μ’…λ£Œλ˜μ–΄ μ•„λž˜ μ½”λ“œλŠ” μ‹€ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.
console.log('[End]');

// μ—λŸ¬2
const $elem = document.querySelector('#1');
// DOMException: Failed to execute 'querySelector' on 'Document': '#1' is not a valid selector.

// μ˜ˆμ™Έ 상황1
// DOM에 button μš”μ†Œκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ querySelector λ©”μ„œλ“œλŠ” μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€μ§€ μ•Šκ³  null을 λ°˜ν™˜ν•œλ‹€.
const $button = document.querySelector('button'); // null

$button.classList.add('disabled');
// TypeError: Cannot read property 'classList' of null
  • μ •μ˜λ˜μ§€ μ•Šμ€ 객체에 λŒ€ν•œ 참쑰둜 μΈν•œ μ—λŸ¬
  • querySelector λ©”μ„œλ“œλŠ” 인수둜 μ „λ‹¬ν•œ λ¬Έμžμ—΄μ΄ CSS μ„ νƒμž 문법에 λ§žμ§€ μ•ŠλŠ” 경우 μ—λŸ¬ λ°œμƒ
  • querySelector λ©”μ„œλ“œλŠ” 인수둜 μ „λ‹¬ν•œ CSS μ„ νƒμž λ¬Έμžμ—΄λ‘œ DOMμ—μ„œ μš”μ†Œ λ…Έλ“œλ₯Ό 찾을 수 μ—†λŠ” 경우 null λ°˜ν™˜

 

λ”°λΌμ„œ μ–Έμ œλ‚˜ μ—λŸ¬λ‚˜ μ˜ˆμ™Έμ μΈ 상황이 λ°œμƒν•  수 μžˆλ‹€λŠ” 것을 μ „μ œν•˜κ³  이에 λŒ€μ‘ν•˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.


try ... catch ... finally λ¬Έ

기본적으둜 μ—λŸ¬ μ—λŸ¬ 처리λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법은 크게 두 가지가 μžˆμŠ΅λ‹ˆλ‹€.

  1. querySelectorλ‚˜ Array#find λ©”μ„œλ“œμ²˜λŸΌ μ˜ˆμ™Έμ μΈ 상황이 λ°œμƒν•˜λ©΄ λ°˜ν™˜ν•˜λŠ” κ°’(null λ˜λŠ” -1)을 if λ¬Έμ΄λ‚˜ 단좕 평가 λ˜λŠ” μ˜΅μ…”λ„ 체이닝 μ—°μ‚°μž(?)λ₯Ό 톡해 확인해 μ²˜λ¦¬ν•˜λŠ” 방법
  2. μ—λŸ¬ 처리 μ½”λ“œλ₯Ό 미리 등둝해 두고 μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ μ—λŸ¬ 처리 μ½”λ“œλ‘œ μ ν”„ν•˜λ„λ‘ ν•˜λŠ” 방법

try ... catch ... filnally 문은 두 번째 λ°©λ²•μœΌλ‘œ 일반적으둜 μ—λŸ¬ 처리(error handling)라고 ν•©λ‹ˆλ‹€.

 

console.log('[Start]');

try {
  // μ‹€ν–‰ν•  μ½”λ“œ(μ—λŸ¬κ°€ λ°œμƒν•  κ°€λŠ₯성이 μžˆλŠ” μ½”λ“œ)
  foo();
} catch (err) {
  // try μ½”λ“œ λΈ”λ‘μ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ 이 μ½”λ“œ λΈ”λ‘μ˜ μ½”λ“œκ°€ μ‹€ν–‰λœλ‹€.
  // errμ—λŠ” try μ½”λ“œ λΈ”λ‘μ—μ„œ λ°œμƒν•œ Error 객체가 μ „λ‹¬λœλ‹€.
  console.error(err); // ReferenceError: foo is not defined
} finally {
  // μ—λŸ¬ λ°œμƒκ³Ό 상관없이 λ°˜λ“œμ‹œ ν•œ 번 μ‹€ν–‰λœλ‹€.
  console.log('finally');
}

// try...catch...finally 문으둜 μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜λ©΄ ν”„λ‘œκ·Έλž¨μ΄ κ°•μ œ μ’…λ£Œλ˜μ§€ μ•ŠλŠ”λ‹€.
console.log('[End]');
  • try μ½”λ“œ 블둝이 μ‹€ν–‰λ˜λ©΄ try μ½”λ“œ 블둝에 ν¬ν•¨λœ λ¬Έ μ€‘μ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ catch 문의 err λ³€μˆ˜μ— 전달
  • catch 문의 err λ³€μˆ˜λŠ” try μ½”λ“œ 블둝에 ν¬ν•¨λœ λ¬Έ μ€‘μ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ μƒμ„±λ˜κ³  catch μ½”λ“œ λΈ”λ‘μ—μ„œλ§Œ 유효
  • finally μ½”λ“œ 블둝은 μ—λŸ¬ λ°œμƒκ³Ό 상관없이 λ°˜λ“œμ‹œ ν•œ 번 μ‹€ν–‰ (μƒλž΅ κ°€λŠ₯)

이처럼 try ... catch ... filnally 문으둜 μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜λ©΄ ν”„λ‘œκ·Έλž¨μ΄ κ°•μ œ μ’…λ£Œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.


Error 객체

Error μƒμ„±μž ν•¨μˆ˜λŠ” μ—λŸ¬λ₯Ό μƒμ„Ένžˆ μ„€λͺ…ν•˜λŠ” μ—λŸ¬ λ©”μ‹œμ§€λ₯Ό 인수둜 전달받을 수 있으며 μ—λŸ¬ 객체λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.

 

const error = new Error('invalid');

 

Error μƒμ„±μž ν•¨μˆ˜κ°€ μƒμ„±ν•œ μ—λŸ¬ κ°μ²΄λŠ” message ν”„λ‘œνΌν‹°μ™€ stack ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§‘λ‹ˆλ‹€.

  • message ν”„λ‘œνΌν‹° κ°’ : Error μƒμ„±μž ν•¨μˆ˜μ— 인수둜 μ „λ‹¬ν•œ μ—λŸ¬ λ©”μ‹œμ§€ 
  • stack ν”„λ‘œνΌν‹° κ°’ : μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚¨ 콜 μŠ€νƒμ˜ 호좜 정보λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ¬Έμžμ—΄μ΄λ©° 디버깅 λͺ©μ μœΌλ‘œ μ‚¬μš©

 

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” λ‹€μŒκ³Ό 같이 Error μƒμ„±μž ν•¨μˆ˜λ₯Ό 포함해 7κ°€μ§€μ˜ Error.prototype을 μƒμ†λ°›λŠ” μ—λŸ¬ 객체λ₯Ό 생성할 수 μžˆλŠ” Error μƒμ„±μž ν•¨μˆ˜λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. 

 

μƒμ„±μž ν•¨μˆ˜ μΈμŠ€ν„΄μŠ€
Error 일반적 μ—λŸ¬ 객체
SyntaxError μžλ°”μŠ€ν¬λ¦½νŠΈ 문법에 λ§žμ§€ μ•ŠλŠ” 문을 해석할 λ•Œ λ°œμƒν•˜λŠ” μ—λŸ¬ 객체
ReferenceError μ°Έμ‘°ν•  수 μ—†λŠ” μ‹λ³„μžλ₯Ό μ°Έμ‘°ν–ˆμ„ λ•Œ λ°œμƒν•˜λŠ” μ—λŸ¬ 객체
TypeError ν”Όμ—°μ‚°μž λ˜λŠ” 인수의 데이터 νƒ€μž…μ΄ μœ νš¨ν•˜μ§€ μ•Šμ„ λ•Œ λ°œμƒν•˜λŠ” μ—λŸ¬ 객체
RangeError μˆ«μžκ°’μ˜ ν—ˆμš© λ²”μœ„λ₯Ό 벗어났을 λ•Œ λ°œμƒν•˜λŠ” μ—λŸ¬ 객체
URIError encodeURI λ˜λŠ” decodeURI ν•¨μˆ˜μ— λΆ€μ μ ˆν•œ 인수λ₯Ό μ „λ‹¬ν–ˆμ„ λ•Œ λ°œμƒν•˜λŠ” μ—λŸ¬ 객체
EvalError eval ν•¨μˆ˜μ—μ„œ λ°œμƒν•˜λŠ” μ—λŸ¬ 객체

 

1 @ 1;    // SyntaxError: Invalid or unexpected token
foo();    // ReferenceError: foo is not defined
null.foo; // TypeError: Cannot read property 'foo' of null
new Array(-1); // RangeError: Invalid array length
decodeURIComponent('%'); // URIError: URI malformed

 


throw λ¬Έ

Error μƒμ„±μž ν•¨μˆ˜λ‘œ μ—λŸ¬ 객체λ₯Ό μƒμ„±ν•œλ‹€κ³  μ—λŸ¬κ°€ λ°œμƒν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λ €λ©΄ try μ½”λ“œ λΈ”λ‘μ—μ„œ throw문으둜 μ—λŸ¬ 객체λ₯Ό λ˜μ Έμ•Ό ν•©λ‹ˆλ‹€.

 

throw ν‘œν˜„μ‹;

 

throw 문의 ν‘œν˜„μ‹μ€ μ–΄λ–€ 값이라도 μƒκ΄€μ—†μ§€λ§Œ 일반적으둜 μ—λŸ¬ 객체λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. μ—λŸ¬λ₯Ό λ˜μ§€λ©΄ catch 문의 μ—λŸ¬ λ³€μˆ˜κ°€ μƒμ„±λ˜κ³  λ˜μ Έμ§„ μ—λŸ¬ 객체가 ν• λ‹Ήλ˜κ³  catch μ½”λ“œ 블둝이 μ‹€ν–‰λ©λ‹ˆλ‹€.

 

try {
  // μ—λŸ¬ 객체λ₯Ό λ˜μ§€λ©΄ catch μ½”λ“œ 블둝이 μ‹€ν–‰λ˜κΈ° μ‹œμž‘ν•œλ‹€.
  throw new Error('something wrong');
} catch (error) {
  console.log(error);
}

 

 

throw 문을 ν™œμš©ν•΄ μ™ΈλΆ€μ—μ„œ 전달받은 콜백 ν•¨μˆ˜λ₯Ό n번만큼 반볡 ν˜ΈμΆœν•˜λŠ” repeat ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•˜λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

// μ™ΈλΆ€μ—μ„œ 전달받은 콜백 ν•¨μˆ˜λ₯Ό n번만큼 반볡 ν˜ΈμΆœν•œλ‹€
const repeat = (n, f) => {
  // λ§€κ°œλ³€μˆ˜ f에 μ „λ‹¬λœ μΈμˆ˜κ°€ ν•¨μˆ˜κ°€ μ•„λ‹ˆλ©΄ TypeErrorλ₯Ό λ°œμƒμ‹œν‚¨λ‹€.
  if (typeof f !== 'function') throw new TypeError('f must be a function');

  for (var i = 0; i < n; i++) {
    f(i); // iλ₯Ό μ „λ‹¬ν•˜λ©΄μ„œ fλ₯Ό 호좜
  }
};

try {
  repeat(2, 1); // 두 번째 μΈμˆ˜κ°€ ν•¨μˆ˜κ°€ μ•„λ‹ˆλ―€λ‘œ TypeErrorκ°€ λ°œμƒ(throw)ν•œλ‹€.
} catch (err) {
  console.error(err); // TypeError: f must be a function
}

 


μ—λŸ¬μ˜ μ „νŒŒ

μ—λŸ¬λŠ” 호좜자(caller) λ°©ν–₯으둜 μ „νŒŒλ©λ‹ˆλ‹€. 즉, 콜 μŠ€νƒμ˜ μ•„λž˜ λ°©ν–₯(μ‹€ν–‰ 쀑인 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ ν‘Έμ‹œλ˜κΈ° 직전에 ν‘Έμ‹œλœ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ λ°©ν–₯)으둜 μ „νŒŒλ©λ‹ˆλ‹€.

 

const foo = () => {
  throw Error('fooμ—μ„œ λ°œμƒν•œ μ—λŸ¬'); // β‘£
};

const bar = () => {
  foo(); // β‘’
};

const baz = () => {
  bar(); // β‘‘
};

try {
  baz(); // β‘ 
} catch (err) {
  console.error(err);
}

 

μœ„ 예제의 호좜 μˆœμ„œλŠ” baz ν•¨μˆ˜ 호좜 -> bar ν•¨μˆ˜ 호좜 -> foo ν•¨μˆ˜ 호좜이며 foo ν•¨μˆ˜κ°€ throwν•œ μ—λŸ¬λŠ” λ‹€μŒκ³Ό 같이 ν˜ΈμΆœμžμ—κ²Œ μ „νŒŒλ˜μ–΄ μ „μ—­μ—μ„œ μΊμΉ˜λ©λ‹ˆλ‹€.

 

 

throw된 μ—λŸ¬λ₯Ό μΊμΉ˜ν•˜μ—¬ 적절히 λŒ€μ‘ν•˜λ©΄ ν”„λ‘œκ·Έλž¨μ„ κ°•μ œ μ’…λ£Œμ‹œν‚€μ§€ μ•Šκ³  μ½”λ“œμ˜ μ‹€ν–‰ 흐름을 볡ꡬ할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

ν•˜μ§€λ§Œ 비동기 ν•¨μˆ˜μΈ setTimeoutμ΄λ‚˜ ν”„λ‘œλ―ΈμŠ€ 후속 처리 λ©”μ„œλ“œμ˜ 콜백 ν•¨μˆ˜λŠ” μ—λŸ¬λ₯Ό μ „νŒŒν•  ν˜ΈμΆœμžκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것을 μ£Όμ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.


[좜처] λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive

https://wikibook.co.kr/mjs/

 

λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ Deep Dive: μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κΈ°λ³Έ κ°œλ…κ³Ό λ™μž‘ 원리

269개의 κ·Έλ¦Όκ³Ό 원리λ₯Ό νŒŒν—€μΉ˜λŠ” μ„€λͺ…μœΌλ‘œ ‘μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κΈ°λ³Έ κ°œλ…κ³Ό λ™μž‘ 원리’λ₯Ό μ΄ν•΄ν•˜μž! μ›ΉνŽ˜μ΄μ§€μ˜ λ‹¨μˆœν•œ 보쑰 κΈ°λŠ₯을 μ²˜λ¦¬ν•˜κΈ° μœ„ν•œ μ œν•œμ μΈ μš©λ„λ‘œ νƒœμ–΄λ‚œ μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 과도

wikibook.co.kr