JavaScript의 오류 처리에 대한 확실한 가이드

게시 됨: 2022-01-24

머피의 법칙은 잘못될 수 있는 것은 결국 잘못될 것이라고 말합니다. 이것은 프로그래밍 세계에서 너무 잘 적용됩니다. 응용 프로그램을 만들면 버그 및 기타 문제가 발생할 가능성이 있습니다. JavaScript의 오류는 그러한 일반적인 문제 중 하나입니다!

소프트웨어 제품의 성공은 제작자가 사용자에게 피해를 주기 전에 이러한 문제를 얼마나 잘 해결할 수 있는지에 달려 있습니다. 그리고 모든 프로그래밍 언어 중에서 JavaScript는 평균적인 오류 처리 설계로 악명이 높습니다.

JavaScript 응용 프로그램을 빌드하는 경우 한 지점 또는 다른 지점에서 데이터 유형을 엉망으로 만들 가능성이 높습니다. 그렇지 않은 경우 undefinednull 로 바꾸거나 삼중 등호 연산자( === )를 이중 등호 연산자( == )로 대체할 수 있습니다.

실수를 하는 것은 인간뿐이다. 이것이 바로 JavaScript에서 오류를 처리하는 데 필요한 모든 것을 보여주는 이유입니다.

이 기사에서는 JavaScript의 기본 오류를 안내하고 발생할 수 있는 다양한 오류에 대해 설명합니다. 그런 다음 이러한 오류를 식별하고 수정하는 방법을 배우게 됩니다. 프로덕션 환경에서 오류를 효과적으로 처리하기 위한 몇 가지 팁도 있습니다.

더 이상 고민하지 않고 시작하겠습니다!

JavaScript 오류란 무엇입니까?

프로그래밍 오류는 프로그램이 정상적으로 작동하지 않는 상황을 나타냅니다. 존재하지 않는 파일을 열려고 하거나 네트워크 연결이 없는 동안 웹 기반 API 끝점에 연결할 때와 같이 프로그램이 당면한 작업을 처리하는 방법을 모르는 경우에 발생할 수 있습니다.

이러한 상황은 프로그램이 진행 방법을 모른다는 오류를 사용자에게 던지도록 합니다. 프로그램은 오류에 대해 가능한 한 많은 정보를 수집한 다음 계속 진행할 수 없다고 보고합니다.

머피의 법칙에 따르면 잘못될 수 있는 것은 결국 잘못될 것입니다 이것은 JavaScript의 세계에서 너무 잘 적용됩니다 이 가이드를 준비 하세요

지능적인 프로그래머는 이러한 시나리오를 예측하고 커버하여 사용자가 "404"와 같은 기술적 오류 메시지를 독립적으로 파악할 필요가 없도록 합니다. 대신 "페이지를 찾을 수 없습니다."라는 훨씬 더 이해하기 쉬운 메시지가 표시됩니다.

JavaScript의 오류는 프로그래밍 오류가 발생할 때마다 표시되는 개체입니다. 이러한 개체에는 오류 유형, 오류를 일으킨 명령문, 오류 발생 시 스택 추적에 대한 충분한 정보가 포함되어 있습니다. JavaScript를 사용하면 프로그래머가 사용자 지정 오류를 만들어 문제를 디버깅할 때 추가 정보를 제공할 수도 있습니다.

오류 속성

이제 JavaScript 오류의 정의가 명확해졌으므로 세부 사항에 대해 알아볼 차례입니다.

JavaScript의 오류에는 오류의 원인과 결과를 이해하는 데 도움이 되는 특정 표준 및 사용자 정의 속성이 있습니다. 기본적으로 JavaScript의 오류에는 세 가지 속성이 있습니다.

  1. message : 오류 메시지를 전달하는 문자열 값
  2. name : 발생한 오류 유형(다음 섹션에서 자세히 다루겠습니다.)
  3. stack : 에러가 발생했을 때 실행된 코드의 스택 트레이스.

또한 오류는 오류를 더 잘 설명하기 위해 columnNumber, lineNumber, fileName 등과 같은 속성을 전달할 수도 있습니다. 그러나 이러한 속성은 표준이 아니며 JavaScript 응용 프로그램에서 생성된 모든 오류 개체에 있을 수도 있고 없을 수도 있습니다.

스택 추적 이해

스택 추적은 예외 또는 경고와 같은 이벤트가 발생할 때 프로그램이 있었던 메서드 호출 목록입니다. 예외가 수반되는 샘플 스택 추적은 다음과 같습니다.

"TypeError: Numeric argument is 예상됨" 오류가 추가 스택 세부 정보와 함께 회색 배경에 표시됩니다.
스택 추적의 예.

보시다시피 오류 이름과 메시지를 인쇄하는 것으로 시작하고 호출된 메소드 목록이 뒤따릅니다. 각 메소드 호출은 소스 코드의 위치와 호출된 행을 나타냅니다. 이 데이터를 사용하여 코드베이스를 탐색하고 오류를 일으키는 코드를 식별할 수 있습니다.

이 메소드 목록은 스택 방식으로 정렬됩니다. 예외가 처음 발생한 위치와 스택 메서드 호출을 통해 전파된 방법을 보여줍니다. 예외에 대한 catch를 구현하면 스택을 통해 전파되고 프로그램이 중단되지 않습니다. 그러나 일부 시나리오에서는 의도적으로 프로그램을 충돌시키기 위해 치명적인 오류를 포착하지 않은 상태로 둘 수 있습니다.

오류 대 예외

대부분의 사람들은 일반적으로 오류와 예외를 같은 것으로 간주합니다. 그러나 그들 사이의 약간이지만 근본적인 차이점에 주목하는 것이 중요합니다.

이것을 더 잘 이해하기 위해 간단한 예를 들어보겠습니다. JavaScript에서 오류를 정의하는 방법은 다음과 같습니다.

 const wrongTypeError = TypeError("Wrong type found, expected character")

다음은 wrongTypeError 객체가 예외가 되는 방법입니다.

 throw wrongTypeError

그러나 대부분의 사람들은 오류 개체를 throw하는 동안 정의하는 약식 형식을 사용하는 경향이 있습니다.

 throw TypeError("Wrong type found, expected character")

이것은 표준 관행입니다. 그러나 개발자가 예외와 오류를 혼동하는 경향이 있는 이유 중 하나입니다. 따라서 작업을 빠르게 완료하기 위해 속기를 사용하더라도 기본 사항을 아는 것이 중요합니다.

JavaScript의 오류 유형

JavaScript에는 사전 정의된 다양한 오류 유형이 있습니다. 프로그래머가 애플리케이션의 오류를 명시적으로 처리하지 않을 때마다 JavaScript 런타임에 의해 자동으로 선택되고 정의됩니다.

이 섹션에서는 JavaScript에서 가장 일반적인 몇 가지 유형의 오류를 안내하고 오류가 발생하는 시기와 이유를 이해합니다.

범위 오류

변수가 유효한 값 범위를 벗어난 값으로 설정되면 RangeError가 발생합니다. 일반적으로 값을 함수에 인수로 전달할 때 발생하며 주어진 값이 함수의 매개변수 범위에 있지 않습니다. 제대로 문서화되지 않은 타사 라이브러리를 사용할 때 올바른 값을 전달하기 위해 인수에 대해 가능한 값의 범위를 알아야 하기 때문에 때때로 수정하기가 까다로울 수 있습니다.

RangeError가 발생하는 일반적인 시나리오는 다음과 같습니다.

  • Array 생성자를 통해 잘못된 길이의 배열을 만들려고 합니다.
  • toExponential() , toPrecision() , toFixed() 등과 같은 숫자 메서드에 잘못된 값 전달
  • normalize() 와 같은 문자열 함수에 잘못된 값을 전달합니다.

참조 오류

ReferenceError는 코드의 변수 참조에 문제가 있을 때 발생합니다. 변수를 사용하기 전에 변수에 대한 값을 정의하는 것을 잊어버렸거나 코드에서 액세스할 수 없는 변수를 사용하려고 할 수 있습니다. 어쨌든 스택 추적을 통해 문제가 있는 변수 참조를 찾고 수정하는 데 충분한 정보를 제공합니다.

ReferenceErrors가 발생하는 일반적인 이유는 다음과 같습니다.

  • 변수 이름에 오타가 있습니다.
  • 범위 외부의 블록 범위 변수에 액세스하려고 합니다.
  • 로드되기 전에 외부 라이브러리(예: jQuery의 $)에서 전역 변수를 참조합니다.

구문 오류

이러한 오류는 코드 구문의 오류를 나타내므로 수정하기 가장 간단한 오류 중 하나입니다. JavaScript는 컴파일되지 않고 해석되는 스크립팅 언어이므로 앱에서 오류가 포함된 스크립트를 실행할 때 발생합니다. 컴파일된 언어의 경우 이러한 오류는 컴파일 중에 식별됩니다. 따라서 앱 바이너리는 수정될 때까지 생성되지 않습니다.

SyntaxErrors가 발생할 수 있는 몇 가지 일반적인 이유는 다음과 같습니다.

  • 역 쉼표 누락
  • 닫는 괄호가 없습니다.
  • 중괄호 또는 기타 문자의 잘못된 정렬

IDE에서 Linting 도구를 사용하여 브라우저에 충돌하기 전에 이러한 오류를 식별하는 것이 좋습니다.

유형 오류

TypeError는 JavaScript 앱에서 가장 흔한 오류 중 하나입니다. 이 오류는 일부 값이 특정 예상 유형이 아닌 것으로 판명될 때 생성됩니다. 발생하는 일반적인 경우는 다음과 같습니다.

  • 메서드가 아닌 개체를 호출합니다.
  • null 또는 정의되지 않은 개체의 속성 액세스 시도
  • 문자열을 숫자로 취급하거나 그 반대로 취급하기

TypeError가 발생할 수 있는 가능성이 훨씬 더 많습니다. 나중에 유명한 사례를 살펴보고 수정하는 방법을 배웁니다.

내부 오류

InternalError 유형은 JavaScript 런타임 엔진에서 예외가 발생할 때 사용됩니다. 코드에 문제가 있음을 나타내거나 나타내지 않을 수 있습니다.

종종 InternalError는 두 가지 시나리오에서만 발생합니다.

  • JavaScript 런타임에 대한 패치 또는 업데이트가 예외를 발생시키는 버그를 수반하는 경우(매우 드물게 발생함)
  • 코드에 JavaScript 엔진에 비해 너무 큰 엔터티가 포함된 경우(예: 너무 많은 스위치 케이스, 너무 큰 배열 이니셜라이저, 너무 많은 재귀)

이 오류를 해결하는 가장 적절한 접근 방식은 오류 메시지를 통해 원인을 식별하고 가능한 경우 앱 로직을 재구성하여 JavaScript 엔진의 갑작스러운 워크로드 급증을 제거하는 것입니다.

URI오류

URIError는 decodeURIComponent 와 같은 전역 URI 처리 기능이 불법적으로 사용될 때 발생합니다. 일반적으로 메서드 호출에 전달된 매개 변수가 URI 표준을 따르지 않아 메서드에서 제대로 구문 분석되지 않았음을 나타냅니다.

기형에 대한 인수만 검사하면 되므로 이러한 오류를 진단하는 것은 일반적으로 쉽습니다.

평가 오류

EvalError는 eval() 함수 호출에 오류가 발생할 때 발생합니다. eval() 함수는 문자열에 저장된 JavaScript 코드를 실행하는 데 사용됩니다. 그러나 eval() 함수를 사용하는 것은 보안 문제로 인해 매우 권장되지 않으며 현재 ECMAScript 사양에서는 더 이상 EvalError 클래스를 throw하지 않으므로 이 오류 유형은 단순히 레거시 JavaScript 코드와의 하위 호환성을 유지하기 위해 존재합니다.

이전 버전의 JavaScript에서 작업하는 경우 이 오류가 발생할 수 있습니다. 어떤 경우든 예외에 대해 eval() 함수 호출에서 실행된 코드를 조사하는 것이 가장 좋습니다.

사용자 정의 오류 유형 생성

JavaScript는 대부분의 시나리오에서 다룰 수 있는 적절한 오류 유형 클래스 목록을 제공하지만 목록이 요구 사항을 충족하지 않는 경우 항상 새 오류 유형을 생성할 수 있습니다. 이러한 유연성의 기초는 JavaScript에서 throw 명령으로 문자 그대로 무엇이든 던질 수 있다는 사실에 있습니다.

따라서 기술적으로 이러한 진술은 완전히 합법적입니다.

 throw 8 throw "An error occurred"

그러나 기본 데이터 유형을 던지면 유형, 이름 또는 수반되는 스택 추적과 같은 오류에 대한 세부 정보가 제공되지 않습니다. 이를 수정하고 오류 처리 프로세스를 표준화하기 위해 Error 클래스가 제공되었습니다. 또한 예외를 발생시키는 동안 기본 데이터 유형을 사용하는 것도 권장하지 않습니다.

Error 클래스를 확장하여 사용자 정의 오류 클래스를 생성할 수 있습니다. 다음은 이 작업을 수행하는 방법의 기본 예입니다.

 class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } }

그리고 다음과 같은 방법으로 사용할 수 있습니다.

 throw ValidationError("Property not found: name")

그런 다음 instanceof 키워드를 사용하여 식별할 수 있습니다.

 try { validateForm() // code that throws a ValidationError } catch (e) { if (e instanceof ValidationError) // do something else // do something else }

JavaScript에서 가장 흔한 10가지 오류

이제 일반적인 오류 유형과 사용자 정의 오류 유형을 만드는 방법을 이해했으므로 JavaScript 코드를 작성할 때 직면하게 될 가장 일반적인 오류를 살펴보겠습니다.

1. 잡히지 않은 RangeError

이 오류는 몇 가지 다양한 시나리오에서 Chrome에서 발생합니다. 첫째, 재귀 함수를 호출하고 종료되지 않는 경우 발생할 수 있습니다. Chrome 개발자 콘솔에서 직접 확인할 수 있습니다.

"Uncaught RangeError: 최대 호출 스택 크기 초과" 오류는 재귀 함수 코드가 위에 있는 빨간색 십자가 아이콘 옆에 빨간색 배경에 표시됩니다.
재귀 함수 호출이 있는 RangeError 예제.

따라서 이러한 오류를 해결하려면 재귀 함수의 경계 케이스를 올바르게 정의해야 합니다. 이 오류가 발생하는 또 다른 이유는 함수의 매개변수 범위를 벗어난 값을 전달한 경우입니다. 다음은 예입니다.

"Uncaught RangeError: toExponential() 인수는 0과 100 사이여야 합니다." 오류는 그 위에 toExponential() 함수 호출이 있는 빨간색 십자 아이콘 옆에 빨간색 배경에 표시됩니다.
toExponential() 호출이 있는 RangeError 예제.

오류 메시지는 일반적으로 코드에 무엇이 잘못되었는지 나타냅니다. 변경하면 해결됩니다.

num = 4. num.toExponential(2). 출력: 4.00e+0.
toExponential() 함수 호출에 대한 출력입니다.

2. 잡히지 않은 TypeError: 속성을 설정할 수 없습니다

이 오류는 정의되지 않은 참조에 속성을 설정할 때 발생합니다. 이 코드로 문제를 재현할 수 있습니다.

 var list list.count = 0

다음은 수신할 출력입니다.

"Uncaught TypeError: Cannot set properties of undefined" 오류는 빨간색 배경에 list.count = 0 할당이 있는 빨간색 십자가 아이콘 옆에 표시됩니다.
TypeError 예.

이 오류를 수정하려면 속성에 액세스하기 전에 값으로 참조를 초기화하세요. 수정되었을 때의 모습은 다음과 같습니다.

{}로 목록을 초기화한 후 list.count = 10으로 설정하면 출력이 10이 됩니다.
TypeError를 수정하는 방법.

3. 잡히지 않은 TypeError: 속성을 읽을 수 없습니다.

이것은 JavaScript에서 가장 자주 발생하는 오류 중 하나입니다. 이 오류는 속성을 읽거나 정의되지 않은 개체에서 함수를 호출하려고 할 때 발생합니다. Chrome 개발자 콘솔에서 다음 코드를 실행하여 매우 쉽게 재현할 수 있습니다.

 var func func.call()

출력은 다음과 같습니다.

"Uncaught TypeError:Cannot read properties of undefined" 오류는 빨간색 배경에 func.call()이 있는 적십자 아이콘 옆에 표시됩니다.
정의되지 않은 함수가 있는 TypeError 예제입니다.

정의되지 않은 개체는 이 오류의 가능한 많은 원인 중 하나입니다. 이 문제의 또 다른 주요 원인은 UI를 렌더링하는 동안 상태를 잘못 초기화하는 것입니다. 다음은 React 애플리케이션의 실제 예입니다.

 import React, { useState, useEffect } from "react"; const CardsList = () => { const [state, setState] = useState(); useEffect(() => { setTimeout(() => setState({ items: ["Card 1", "Card 2"] }), 2000); }, []); return ( <> {state.items.map((item) => ( <li key={item}>{item}</li> ))} </> ); }; export default CardsList;

앱은 빈 상태 컨테이너로 시작하고 2초 지연 후 일부 항목과 함께 제공됩니다. 네트워크 호출을 모방하기 위해 지연이 설정됩니다. 네트워크가 매우 빠르더라도 구성 요소가 적어도 한 번 렌더링되기 때문에 약간의 지연이 발생합니다. 이 앱을 실행하려고 하면 다음 오류가 표시됩니다.

"undefined is not an object" 오류가 회색 배경에 표시됩니다.
브라우저의 TypeError 스택 추적.

이는 렌더링 시 상태 컨테이너가 정의되지 않았기 때문입니다. 따라서 속성 items 이 없습니다. 이 오류를 수정하는 것은 쉽습니다. 상태 컨테이너에 초기 기본값을 제공하기만 하면 됩니다.

 // ... const [state, setState] = useState({items: []}); // ...

이제 설정된 지연 후에 앱에 유사한 출력이 표시됩니다.

"카드 1"과 "카드 2"를 읽는 두 항목이 있는 글머리 기호 목록입니다.
코드 출력.

코드의 정확한 수정은 다를 수 있지만 여기서 핵심은 변수를 사용하기 전에 항상 변수를 적절하게 초기화하는 것입니다.

4. TypeError: 'undefined'는 객체가 아닙니다.

이 오류는 정의되지 않은 개체의 속성에 액세스하거나 메서드를 호출하려고 할 때 Safari에서 발생합니다. 위와 동일한 코드를 실행하여 오류를 직접 재현할 수 있습니다.

"TypeError: undefined is not an object" 오류는 빨간색 배경에 func.call() 메서드 호출이 있는 빨간색 느낌표 아이콘 옆에 표시됩니다.
정의되지 않은 함수가 있는 TypeError 예제입니다.

이 오류에 대한 솔루션도 동일합니다. 변수를 올바르게 초기화했는지 확인하고 속성 또는 메서드에 액세스할 때 변수가 정의되지 않았는지 확인합니다.

5. TypeError: null은 객체가 아닙니다.

이것은 다시 이전 오류와 유사합니다. Safari에서 발생하며 두 오류의 유일한 차이점은 속성 또는 메서드가 액세스되는 개체가 undefined 대신 null 일 때 발생한다는 것입니다. 다음 코드를 실행하여 이를 재현할 수 있습니다.

 var func = null func.call()

다음은 수신할 출력입니다.

"TypeError: null은 개체가 아닙니다." 오류 메시지가 빨간색 느낌표 아이콘 옆에 빨간색 배경에 표시됩니다.
null 함수가 있는 TypeError 예제.

null 은 변수에 명시적으로 설정되고 JavaScript에 의해 자동으로 할당되지 않는 값이기 때문입니다. 이 오류는 null 로 설정한 변수에 직접 액세스하려는 경우에만 발생할 수 있습니다. 따라서 코드를 다시 방문하여 작성한 논리가 올바른지 여부를 확인해야 합니다.

6. TypeError: 'length' 속성을 읽을 수 없습니다.

이 오류는 null 또는 undefined 개체의 길이를 읽으려고 할 때 Chrome에서 발생합니다. 이 문제의 원인은 이전 문제와 유사하지만 목록을 처리하는 동안 매우 자주 발생합니다. 따라서 특별한 언급이 필요합니다. 문제를 재현하는 방법은 다음과 같습니다.

빨간색 배경에 myButton.length 호출이 있는 적십자 아이콘 옆에 "Uncaught TypeError: Cannot read property 'length' of undefined" 오류가 표시됩니다.
정의되지 않은 개체가 있는 TypeError 예제입니다.

그러나 최신 버전의 Chrome에서는 이 오류가 Uncaught TypeError: Cannot read properties of undefined 로 보고됩니다. 현재 모습은 다음과 같습니다.

빨간색 배경 위에 myButton.length 호출이 있는 빨간색 배경에 "Uncaught TypeError:Cannot read properties of undefined" 오류가 표시됩니다.
최신 Chrome 버전에서 정의되지 않은 개체가 있는 TypeError 예입니다.

다시 한 번 수정 사항은 액세스하려는 길이의 객체가 존재하고 null 로 설정되지 않았는지 확인하는 것입니다.

7. TypeError: 'undefined'는 함수가 아닙니다.

이 오류는 스크립트에 존재하지 않는 메서드를 호출하려고 하거나 호출 컨텍스트에서 참조할 수 있지만 참조할 수 없는 메서드를 호출할 때 발생합니다. 이 오류는 일반적으로 Google 크롬에서 발생하며 오류를 발생시키는 코드 행을 확인하여 해결할 수 있습니다. 오타를 발견하면 수정하고 문제가 해결되는지 확인하십시오.

코드에서 자체 참조 키워드 this 를 사용한 경우 컨텍스트에 적절하게 바인딩되지 않은 경우 this 오류가 발생할 수 있습니다. 다음 코드를 고려하십시오.

 function showAlert() { alert("message here") } document.addEventListener("click", () => { this.showAlert(); })

위의 코드를 실행하면 우리가 논의한 오류가 발생합니다. 이벤트 리스너로 전달된 익명 함수가 document 컨텍스트에서 실행되기 때문에 발생합니다.

대조적으로, showAlert 함수는 window 컨텍스트에서 정의됩니다.

이 문제를 해결하려면 bind() 메서드로 함수를 바인딩하여 함수에 대한 적절한 참조를 전달해야 합니다.

 document.addEventListener("click", this.showAlert.bind(this))

8. ReferenceError: 이벤트가 정의되지 않았습니다.

이 오류는 호출 범위에 정의되지 않은 참조에 액세스하려고 할 때 발생합니다. 이는 이벤트가 종종 콜백 함수에서 event 라는 참조를 제공하기 때문에 이벤트를 처리할 때 발생합니다. 이 오류는 함수의 매개변수에 이벤트 인수를 정의하는 것을 잊었거나 철자가 틀린 경우에 발생할 수 있습니다.

이 오류는 Internet Explorer 또는 Google Chrome에서는 발생하지 않을 수 있지만(IE는 전역 이벤트 변수를 제공하고 Chrome은 이벤트 변수를 핸들러에 자동으로 연결하기 때문에) Firefox에서는 발생할 수 있습니다. 따라서 이러한 작은 실수에 주의하는 것이 좋습니다.

9. TypeError: 상수 변수에 할당

이것은 부주의에서 발생하는 오류입니다. 상수 변수에 새 값을 할당하려고 하면 다음과 같은 결과가 나타납니다.

"Uncaught TypeError: Assignment to constant variable" 오류는 빨간색 배경에 func = 6 할당이 있는 적십자 아이콘 옆에 표시됩니다.
상수 객체 할당이 있는 TypeError 예제.

지금 당장은 쉽게 고칠 수 있지만 수백 개의 변수 선언과 그 중 하나가 let 대신 const 로 잘못 정의되었다고 상상해 보십시오! PHP와 같은 다른 스크립팅 언어와 달리 JavaScript에서 상수 및 변수 선언 스타일 사이에는 최소한의 차이가 있습니다. 따라서 이 오류에 직면했을 때 먼저 선언을 확인하는 것이 좋습니다. 해당 참조가 상수라는 사실을 잊고 변수로 사용하는 경우에도 이 오류가 발생할 수 있습니다. 이는 부주의하거나 앱 논리의 결함을 나타냅니다. 이 문제를 해결하려고 할 때 이것을 확인하십시오.

10. (알 수 없음): 스크립트 오류

스크립트 오류는 타사 스크립트가 브라우저에 오류를 보낼 때 발생합니다. 타사 스크립트가 앱과 다른 도메인에 속하기 때문에 이 오류 뒤에 (알 수 없음) 이 표시됩니다. 브라우저는 타사 스크립트에서 민감한 정보가 누출되는 것을 방지하기 위해 다른 세부 정보를 숨깁니다.

전체 세부 정보를 모르면 이 오류를 해결할 수 없습니다. 다음은 오류에 대한 추가 정보를 얻기 위해 수행할 수 있는 작업입니다.

  1. 스크립트 태그에 crossorigin 속성을 추가하십시오.
  2. 스크립트를 호스팅하는 서버에서 올바른 Access-Control-Allow-Origin 헤더를 설정하십시오.
  3. [선택 사항] 스크립트를 호스팅하는 서버에 액세스할 수 없는 경우 프록시를 사용하여 요청을 서버에 전달하고 올바른 헤더를 사용하여 클라이언트에 다시 전달하는 것을 고려할 수 있습니다.

오류에 대한 세부 정보에 액세스할 수 있으면 문제를 해결하도록 설정할 수 있습니다. 이 문제는 타사 라이브러리나 네트워크에 있을 수 있습니다.

JavaScript에서 오류를 식별하고 방지하는 방법

위에서 논의한 오류는 JavaScript에서 가장 흔하고 빈번하지만 몇 가지 예에 의존하는 것만으로는 결코 충분하지 않다는 것을 알게 될 것입니다. JavaScript 애플리케이션을 개발하는 동안 모든 유형의 오류를 감지하고 방지하는 방법을 이해하는 것이 중요합니다. 다음은 JavaScript에서 오류를 처리하는 방법입니다.

수동으로 오류를 던지고 잡아라

수동으로 또는 런타임에 의해 발생한 오류를 처리하는 가장 기본적인 방법은 오류를 잡는 것입니다. 대부분의 다른 언어와 마찬가지로 JavaScript는 오류를 처리하기 위한 일련의 키워드를 제공합니다. JavaScript 앱에서 오류를 처리하기 위해 설정하기 전에 각각을 심층적으로 아는 것이 중요합니다.

던지다

세트의 첫 번째이자 가장 기본적인 키워드는 throw 입니다. 명백히, throw 키워드는 JavaScript 런타임에서 수동으로 예외를 생성하기 위해 오류를 발생시키는 데 사용됩니다. 우리는 이미 이 글의 앞부분에서 이에 대해 논의했으며 다음은 이 키워드의 중요성에 대한 요지입니다.

  • 숫자, 문자열 및 Error 개체를 포함하여 무엇이든 throw 수 있습니다.
  • 그러나 문자열 및 숫자와 같은 기본 데이터 유형은 오류에 대한 디버그 정보를 전달하지 않으므로 던지지 않는 것이 좋습니다.
  • 예: throw TypeError("Please provide a string")

노력하다

try 키워드는 코드 블록이 예외를 throw할 수 있음을 나타내는 데 사용됩니다. 구문은 다음과 같습니다.

 try { // error-prone code here }

오류를 효과적으로 처리하려면 catch 블록이 항상 try 블록을 따라야 한다는 점에 유의하는 것이 중요합니다.

잡다

catch 키워드는 catch 블록을 만드는 데 사용됩니다. 이 코드 블록은 후행 try 블록이 잡는 오류를 처리합니다. 구문은 다음과 같습니다.

 catch (exception) { // code to handle the exception here }

다음은 try 블록과 catch 블록을 함께 구현하는 방법입니다.

 try { // business logic code } catch (exception) { // error handling code }

C++ 또는 Java와 달리 JavaScript에서는 try 블록에 여러 catch 블록을 추가할 수 없습니다. 이것은 당신이 이것을 할 수 없다는 것을 의미합니다:

 try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } } catch (exception) { if (exception instanceof RangeError) { // do something } }

대신 단일 catch 블록 내에서 if...else 문 또는 switch case 문을 사용하여 가능한 모든 오류 사례를 처리할 수 있습니다. 다음과 같이 보일 것입니다.

 try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } else if (exception instanceof RangeError) { // do something else } }

마지막으로

finally 키워드는 오류가 처리된 후 실행되는 코드 블록을 정의하는 데 사용됩니다. 이 블록은 try 및 catch 블록 후에 실행됩니다.

또한 finally 블록은 다른 두 블록의 결과에 관계없이 실행됩니다. 즉, catch 블록이 오류를 완전히 처리할 수 없거나 catch 블록에서 오류가 발생하더라도 프로그램이 충돌하기 전에 인터프리터가 finally 블록의 코드를 실행합니다.

유효한 것으로 간주되려면 JavaScript의 try 블록 다음에 catch 또는 finally 블록이 와야 합니다. 이들 중 어느 것도 없으면 인터프리터는 SyntaxError를 발생시킵니다. 따라서 오류를 처리할 때 적어도 둘 중 하나를 사용하여 try 블록을 따라야 합니다.

onerror() 메서드를 사용하여 전역적으로 오류 처리

onerror() 메서드는 모든 HTML 요소에서 발생할 수 있는 오류를 처리하기 위해 사용할 수 있습니다. 예를 들어, img 태그가 URL이 지정된 이미지를 찾을 수 없으면 사용자가 오류를 처리할 수 있도록 해당 onerror 메서드를 실행합니다.

일반적으로 img 태그가 대체할 onerror 호출에 다른 이미지 URL을 제공합니다. JavaScript를 통해 이를 수행하는 방법은 다음과 같습니다.

 const image = document.querySelector("img") image.onerror = (event) => { console.log("Error occurred: " + event) }

그러나 이 기능을 사용하여 앱에 대한 전역 오류 처리 메커니즘을 만들 수 있습니다. 방법은 다음과 같습니다.

 window.onerror = (event) => { console.log("Error occurred: " + event) }

이 이벤트 핸들러를 사용하면 코드에 있는 여러 try...catch 블록을 제거하고 이벤트 처리와 유사한 앱의 오류 처리를 중앙 집중화할 수 있습니다. SOLID 디자인 원칙에서 단일 책임 원칙을 유지하기 위해 여러 오류 핸들러를 창에 연결할 수 있습니다. 인터프리터는 적절한 핸들러에 도달할 때까지 모든 핸들러를 순환합니다.

콜백을 통해 오류 전달

단순하고 선형적인 함수를 사용하면 오류 처리가 단순하게 유지되지만 콜백은 문제를 복잡하게 만들 수 있습니다.

다음 코드를 고려하십시오.

경쟁 우위를 제공하는 호스팅 솔루션이 필요하십니까? Kinsta는 놀라운 속도, 최첨단 보안 및 자동 크기 조정 기능을 제공합니다. 우리의 계획을 확인하십시오

 const calculateCube = (number, callback) => { setTimeout(() => { const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) calculateCube(4, callback)

위의 함수는 함수가 작업을 처리하는 데 시간이 걸리고 나중에 콜백의 도움으로 결과를 반환하는 비동기 조건을 보여줍니다.

함수 호출에서 4 대신 문자열을 입력하려고 하면 결과적으로 NaN 이 표시됩니다.

이것은 제대로 처리해야 합니다. 방법은 다음과 같습니다.

 const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") throw new Error("Numeric argument is expected") const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) try { calculateCube(4, callback) } catch (e) { console.log(e) }

이것은 문제를 이상적으로 해결해야 합니다. 그러나 함수 호출에 문자열을 전달하려고 하면 다음과 같은 메시지가 표시됩니다.

적십자 아이콘 옆의 진한 빨간색 배경에 "캐치되지 않은 오류: 숫자 인수가 필요합니다"라는 오류가 표시됩니다.
잘못된 인수가 있는 오류 예입니다.

함수를 호출하는 동안 try-catch 블록을 구현했지만 여전히 오류가 포착되지 않았다고 표시됩니다. 시간 초과 지연으로 인해 catch 블록이 실행된 후 오류가 발생합니다.

이는 예상치 못한 지연이 발생하는 네트워크 호출에서 빠르게 발생할 수 있습니다. 앱을 개발하는 동안 이러한 경우를 처리해야 합니다.

다음은 콜백에서 오류를 올바르게 처리하는 방법입니다.

 const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") { callback(new TypeError("Numeric argument is expected")) return } const cube = number * number * number callback(null, cube) }, 2000) } const callback = (error, result) => { if (error !== null) { console.log(error) return } console.log(result) } try { calculateCube('hey', callback) } catch (e) { console.log(e) }

이제 콘솔의 출력은 다음과 같습니다.

어두운 회색 배경에 "TypeError: Numeric 인수가 필요합니다"라는 메시지가 표시됩니다.
잘못된 인수가 있는 TypeError 예입니다.

이는 오류가 적절하게 처리되었음을 나타냅니다.

약속의 오류 처리

대부분의 사람들은 비동기 활동을 처리하기 위해 promise를 선호하는 경향이 있습니다. Promise에는 또 다른 이점이 있습니다. 거부된 Promise는 스크립트를 종료하지 않습니다. 그러나 약속의 오류를 처리하려면 여전히 catch 블록을 구현해야 합니다. 이것을 더 잘 이해하기 위해 Promises를 사용하여 computeCube calculateCube() 함수를 다시 작성해 보겠습니다.

 const delay = ms => new Promise(res => setTimeout(res, ms)); const calculateCube = async (number) => { if (typeof number !== "number") throw Error("Numeric argument is expected") await delay(5000) const cube = number * number * number return cube } try { calculateCube(4).then(r => console.log(r)) } catch (e) { console.log(e) }

이전 코드의 타임아웃은 이해를 위해 delay 기능으로 분리되었습니다. 4 대신 문자열을 입력하려고 하면 다음과 유사한 출력이 표시됩니다.

적십자 아이콘 옆에 어두운 회색 배경에 "Uncaught (in promise) Error: Numeric argument is 예상됨" 오류가 표시됩니다.
Promise에 잘못된 인수가 있는 TypeError 예제.

다시 말하지만 이것은 다른 모든 것이 실행을 완료한 후 오류를 발생시키는 Promise 때문입니다. 이 문제에 대한 해결책은 간단합니다. 다음과 같이 약속 체인에 catch() 호출을 추가하기만 하면 됩니다.

 calculateCube("hey") .then(r => console.log(r)) .catch(e => console.log(e))

이제 출력은 다음과 같습니다.

어두운 회색 배경에 "오류: 숫자 인수가 필요합니다"라는 메시지가 표시됩니다.
잘못된 인수가 있는 TypeError 예제를 처리했습니다.

Promise로 오류를 처리하는 것이 얼마나 쉬운지 관찰할 수 있습니다. 또한, finally() 블록과 promise 호출을 연결하여 오류 처리가 완료된 후 실행할 코드를 추가할 수 있습니다.

또는 전통적인 try-catch-finally 기술을 사용하여 약속의 오류를 처리할 수도 있습니다. 이 경우 약속 호출은 다음과 같습니다.

 try { let result = await calculateCube("hey") console.log(result) } catch (e) { console.log(e) } finally { console.log('Finally executed") }

그러나 이것은 비동기 함수 내에서만 작동합니다. 따라서 Promise의 오류를 처리하는 가장 선호되는 방법은 catch 를 연결하고 finally 으로 Promise 호출에 연결하는 것입니다.

throw/catch vs onerror() vs Callbacks vs Promises: 어느 것이 최고입니까?

4가지 방법을 사용할 수 있으므로 주어진 사용 사례에 가장 적합한 방법을 선택하는 방법을 알아야 합니다. 스스로 결정할 수 있는 방법은 다음과 같습니다.

던지다/잡다

대부분 이 방법을 사용하게 될 것입니다. catch 블록 내에서 가능한 모든 오류에 대한 조건을 구현하고 try 블록 이후에 일부 메모리 정리 루틴을 실행해야 하는 경우 finally 블록을 포함하는 것을 기억하십시오.

그러나 너무 많은 try/catch 블록은 코드를 유지 관리하기 어렵게 만들 수 있습니다. 이러한 상황에 처한 경우 전역 처리기 또는 약속 메서드를 통해 오류를 처리할 수 있습니다.

비동기식 try/catch 블록과 promise의 catch() 중 하나를 결정할 때 비동기식 try/catch 블록을 사용하는 것이 좋습니다. 비동기식 try/catch 블록은 코드를 선형적이고 디버그하기 쉽게 만들기 때문입니다.

오류()

앱이 많은 오류를 처리해야 하고 코드베이스 전체에 잘 분산될 수 있다는 것을 알고 있을 때 onerror() 메서드를 사용하는 것이 가장 좋습니다. onerror 메서드를 사용하면 애플리케이션에서 처리하는 또 다른 이벤트인 것처럼 오류를 처리할 수 있습니다. 여러 오류 처리기를 정의하고 초기 렌더링에서 앱 창에 연결할 수 있습니다.

그러나 onerror() 메서드는 오류 범위가 적은 소규모 프로젝트에서 설정하기가 불필요하게 어려울 수 있음을 기억해야 합니다. 앱이 너무 많은 오류를 발생시키지 않을 것이라고 확신하는 경우 기존의 throw/catch 방법이 가장 적합합니다.

콜백과 약속

콜백 및 약속의 오류 처리는 코드 디자인 및 구조로 인해 다릅니다. 그러나 코드를 작성하기 전에 이 두 가지 중 하나를 선택한다면 Promise를 사용하는 것이 가장 좋습니다.

이는 약속에 catch()finally() 블록을 연결하여 오류를 쉽게 처리하기 위한 내장 구조가 있기 때문입니다. 이 방법은 추가 인수를 정의하거나 기존 인수를 재사용하여 오류를 처리하는 것보다 쉽고 깨끗합니다.

Git 리포지토리로 변경 사항 추적

코드베이스의 수동 실수로 인해 많은 오류가 자주 발생합니다. 코드를 개발하거나 디버깅하는 동안 불필요한 변경을 수행하여 코드베이스에 새로운 오류가 나타날 수 있습니다. 자동화된 테스트는 모든 변경 후에 코드를 확인하는 좋은 방법입니다. 그러나 문제가 있는 경우에만 알려줄 수 있습니다. 코드를 자주 백업하지 않으면 이전에 잘 작동하던 함수나 스크립트를 수정하는 데 시간을 낭비하게 됩니다.

이것이 git이 역할을 하는 곳입니다. 적절한 커밋 전략을 사용하면 git 기록을 백업 시스템으로 사용하여 개발을 통해 발전한 코드를 볼 수 있습니다. 이전 커밋을 쉽게 탐색하고 이전에는 제대로 작동했지만 관련 없는 변경 후에는 오류가 발생한 함수 버전을 찾을 수 있습니다.

그런 다음 이전 코드를 복원하거나 두 버전을 비교하여 무엇이 잘못되었는지 확인할 수 있습니다. GitHub Desktop 또는 GitKraken과 같은 최신 웹 개발 도구를 사용하면 이러한 변경 사항을 나란히 시각화하고 실수를 빠르게 파악할 수 있습니다.

오류를 줄이는 데 도움이 되는 습관은 코드를 크게 변경할 때마다 코드 검토를 실행하는 것입니다. 팀에서 작업하는 경우 풀 리퀘스트를 생성하고 팀원이 철저히 검토하도록 할 수 있습니다. 이것은 두 번째 눈을 사용하여 실수했을 수 있는 오류를 찾아내는 데 도움이 됩니다.

JavaScript에서 오류 처리를 위한 모범 사례

위에서 언급한 방법은 다음 JavaScript 응용 프로그램에 대한 강력한 오류 처리 접근 방식을 설계하는 데 도움이 됩니다. 그러나 오류 방지를 최대한 활용하려면 구현하는 동안 몇 가지 사항을 염두에 두는 것이 가장 좋습니다. 다음은 도움이 될 몇 가지 팁입니다.

1. 작업 예외 처리 시 사용자 지정 오류 사용

응용 프로그램의 고유한 경우에 대해 오류 처리를 사용자 지정하는 방법에 대한 아이디어를 제공하기 위해 이 가이드 초반에 사용자 지정 오류를 도입했습니다. 가능한 경우 일반 Error 클래스 대신 사용자 지정 오류를 사용하는 것이 좋습니다. 오류에 대해 호출 환경에 더 많은 컨텍스트 정보를 제공하기 때문입니다.

또한 사용자 지정 오류를 사용하면 호출 환경에 오류가 표시되는 방식을 조정할 수 있습니다. 즉, 원하는 때 특정 세부 정보를 숨기거나 오류에 대한 추가 정보를 표시하도록 선택할 수 있습니다.

필요에 따라 오류 내용의 형식을 지정할 수 있습니다. 이렇게 하면 오류가 해석되고 처리되는 방식을 더 잘 제어할 수 있습니다.

2. 예외를 삼키지 마십시오

가장 시니어 개발자라도 종종 코드 깊숙한 곳에서 예외 수준을 소비하는 초보적인 실수를 범합니다.

선택적으로 실행할 수 있는 코드가 있는 상황이 발생할 수 있습니다. 작동하면 훌륭합니다. 그렇지 않은 경우 이에 대해 아무 조치도 취할 필요가 없습니다.

이러한 경우 이 코드를 try 블록에 넣고 빈 catch 블록을 첨부하고 싶은 경우가 많습니다. 그러나 이렇게 하면 어떤 종류의 오류를 일으키고 빠져나갈 수 있도록 해당 코드 조각을 열어 둡니다. 이것은 큰 코드베이스와 그렇게 좋지 않은 오류 관리 구조의 많은 인스턴스가 있는 경우 위험할 수 있습니다.

예외를 처리하는 가장 좋은 방법은 모든 예외가 처리될 수준을 결정하고 그 수준까지 올리는 것입니다. 이 수준은 컨트롤러(MVC 아키텍처 앱에서) 또는 미들웨어(기존 서버 지향 앱에서)일 수 있습니다.

이렇게 하면 앱에서 발생하는 모든 오류를 찾을 수 있는 위치를 알 수 있고 오류에 대해 아무 조치도 취하지 않는 것을 의미하더라도 해결 방법을 선택할 수 있습니다.

3. 로그 및 오류 경고에 대한 중앙 집중식 전략 사용

오류 기록은 종종 오류 처리의 필수적인 부분입니다. 오류 로깅을 위한 중앙 집중식 전략을 개발하지 못하는 사람들은 앱 사용에 대한 중요한 정보를 놓칠 수 있습니다.

앱의 이벤트 로그는 오류에 대한 중요한 데이터를 파악하고 신속하게 디버그하는 데 도움이 될 수 있습니다. 앱에 적절한 알림 메커니즘이 설정되어 있으면 사용자 기반의 많은 부분에 도달하기 전에 앱에서 오류가 발생했을 때 알 수 있습니다.

사전 구축된 로거를 사용하거나 필요에 맞게 생성하는 것이 좋습니다. 수준(경고, 디버그, 정보 등)에 따라 오류를 처리하도록 이 로거를 구성할 수 있으며 일부 로거는 원격 로깅 서버에 즉시 로그를 보내기까지 합니다. 이렇게 하면 활성 사용자와 함께 응용 프로그램의 논리가 수행되는 방식을 볼 수 있습니다.

4. 사용자에게 오류에 대해 적절하게 알림

오류 처리 전략을 정의할 때 명심해야 할 또 다른 좋은 점은 사용자를 염두에 두는 것입니다.

앱의 정상적인 기능을 방해하는 모든 오류는 사용자에게 문제가 발생했음을 알리기 위해 사용자에게 가시적인 경고를 표시하여 사용자가 해결 방법을 시도할 수 있도록 해야 합니다. 작업 재시도 또는 로그아웃한 후 다시 로그인과 같은 오류에 대한 빠른 수정 사항을 알고 있는 경우 실시간으로 사용자 경험을 수정하는 데 도움이 되도록 경고에 이를 언급해야 합니다.

일상적인 사용자 경험을 방해하지 않는 오류의 경우 경고를 표시하지 않고 나중에 해결하기 위해 원격 서버에 오류를 기록하는 것을 고려할 수 있습니다.

5. 미들웨어(Node.js) 구현

Node.js 환경은 서버 애플리케이션에 기능을 추가하는 미들웨어를 지원합니다. 이 기능을 사용하여 서버에 대한 오류 처리 미들웨어를 만들 수 있습니다.

미들웨어 사용의 가장 중요한 이점은 모든 오류가 한 곳에서 중앙 집중식으로 처리된다는 것입니다. 테스트 목적으로 이 설정을 쉽게 활성화/비활성화하도록 선택할 수 있습니다.

기본 미들웨어를 만드는 방법은 다음과 같습니다.

const logError = err => { console.log("ERROR: " + String(err)) } const errorLoggerMiddleware = (err, req, res, next) => { logError(err) next(err) } const returnErrorMiddleware = (err, req, res, next) => { res.status(err.statusCode || 500) .send(err.message) } module.exports = { logError, errorLoggerMiddleware, returnErrorMiddleware }

그런 다음 앱에서 이 미들웨어를 다음과 같이 사용할 수 있습니다.

 const { errorLoggerMiddleware, returnErrorMiddleware } = require('./errorMiddleware') app.use(errorLoggerMiddleware) app.use(returnErrorMiddleware)

이제 미들웨어 내부에 사용자 정의 로직을 정의하여 오류를 적절하게 처리할 수 있습니다. 더 이상 코드베이스 전체에 걸쳐 개별 오류 처리 구문을 구현하는 것에 대해 걱정할 필요가 없습니다.

6. 앱을 다시 시작하여 프로그래머 오류(Node.js) 처리

Node.js 앱에서 프로그래머 오류가 발생하면 예외가 발생하고 앱을 닫으려고 하지 않을 수 있습니다. 이러한 오류에는 높은 CPU 소비, 메모리 팽창 또는 메모리 누수와 같은 프로그래머 실수로 인해 발생하는 문제가 포함될 수 있습니다. 이를 처리하는 가장 좋은 방법은 Node.js 클러스터 모드 또는 PM2와 같은 고유 도구를 통해 앱을 충돌시켜 정상적으로 앱을 다시 시작하는 것입니다. 이렇게 하면 사용자 작업 시 앱이 충돌하여 끔찍한 사용자 경험을 제공하지 않도록 할 수 있습니다.

7. 잡히지 않은 예외를 모두 잡아라(Node.js)

앱에서 발생할 수 있는 모든 가능한 오류를 다뤘는지 확신할 수 없습니다. 따라서 앱에서 포착되지 않은 모든 예외를 포착하기 위한 대체 전략을 구현하는 것이 필수적입니다.

방법은 다음과 같습니다.

 process.on('uncaughtException', error => { console.log("ERROR: " + String(error)) // other handling mechanisms })

또한 발생한 오류가 표준 예외인지 사용자 정의 작동 오류인지 식별할 수 있습니다. 결과에 따라 프로세스를 종료하고 다시 시작하여 예기치 않은 동작을 방지할 수 있습니다.

8. 처리되지 않은 모든 약속 거부를 잡아라(Node.js).

가능한 모든 예외를 처리할 수 없는 것과 마찬가지로 모든 가능한 약속 거부를 처리하지 못할 가능성이 높습니다. 그러나 예외와 달리 약속 거부는 오류를 발생시키지 않습니다.

따라서 거부된 중요한 약속이 경고로 누락되어 앱이 예기치 않은 동작에 빠질 가능성이 있는 상태로 남을 수 있습니다. 따라서 약속 거부를 처리하기 위한 대체 메커니즘을 구현하는 것이 중요합니다.

방법은 다음과 같습니다.

 const promiseRejectionCallback = error => { console.log("PROMISE REJECTED: " + String(error)) } process.on('unhandledRejection', callback)
응용 프로그램을 만들면 버그 및 기타 문제도 만들 가능성이 있습니다. 이 가이드의 도움을 받아 문제를 처리하는 방법을 알아보세요 ️ 트윗하려면 클릭하세요

요약

다른 프로그래밍 언어와 마찬가지로 오류는 JavaScript에서 매우 빈번하고 자연스럽습니다. 어떤 경우에는 사용자에게 올바른 응답을 나타내기 위해 의도적으로 오류를 발생시켜야 할 수도 있습니다. 따라서 그들의 해부학과 유형을 이해하는 것이 매우 중요합니다.

또한 오류를 식별하고 애플리케이션 중단을 방지하기 위해 올바른 도구와 기술을 갖추고 있어야 합니다.

대부분의 경우 모든 유형의 JavaScript 응용 프로그램에 대해 신중하게 실행하여 오류를 처리하는 견고한 전략이면 충분합니다.

아직 해결하지 못한 다른 JavaScript 오류가 있습니까? JS 오류를 건설적으로 처리하는 기술이 있습니까? 아래 의견에 알려주십시오!