댓글 검색 목록

[javascript] JavaScript의 오류 처리에 대한 대부분의 완전한 가이드

페이지 정보

작성자 운영자 작성일 20-08-23 12:54 조회 638 댓글 0

프로그래밍 오류는 무엇입니까? 


우리 프로그램에서 일이 항상 잘 진행되는 것은 아닙니다. 


특히 프로그램을 중지하거나 잘못된 일이 발생하면 사용자에게 알리고 싶은 상황이 있습니다.


https://www.valentinog.com/blog/error/ 


예를 들면 :

  • 프로그램이 존재하지 않는 파일을 열려고 했습니다.
  • 네트워크 연결이 끊어졌습니다.
  • 사용자가 잘못된 입력을 입력했습니다.


이 모든 경우에 우리는 프로그래머로서 오류를 생성하거나 프로그래밍 엔진이 우리를 위해 일부를 생성하도록 합니다.


오류를 생성 한 후 사용자에게 메시지로 알리거나 실행을 완전히 중지 할 수 있습니다.


JavaScript의 오류는 무엇입니까? 


JavaScript의 오류는 객체이며 나중에 프로그램을 중지하기 위해 발생합니다.


JavaScript에서 새로운 오류를 생성하기 위해 적절한 생성자 함수를 호출합니다. 예를 들어, 새로운 일반 오류를 생성하려면 다음을 수행 할 수 있습니다.


const err = new Error("Something bad happened!");


오류 개체를 만들 때 new 키워드를 생략 할 수도 있습니다.


const err = Error("Something bad happened!");


생성 된 오류 개체는 세 가지 속성을 제공합니다.


  • message: 오류 메시지가 있는 문자열
  • name: 오류의 유형.
  • stack: 함수 실행의 스택 추적.

예를 들어 적절한 메시지가 포함 된 새 TypeError 객체를 생성하면 메시지에는 실제 오류 문자열이 포함되고 이름은 "TypeError"가 됩니다.



const wrongType = TypeError("Wrong type given, expected number");

wrongType.message; // "Wrong type given, expected number"
wrongType.name; // "TypeError"


Firefox는 또한 columnNumber, filename 및 lineNumber와 같은 비표준 속성에 대한 무리를 구현합니다.


JavaScript의 많은 유형의 오류 


JavaScript에는 다음과 같은 여러 유형의 오류가 있습니다.

  • Error
  • EvalError
  • InternalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

이러한 모든 오류 유형은 새 오류 객체를 반환하기 위한 실제 생성자 함수입니다.


코드에서 가장 일반적인 두 가지 유형 인 Error 및 TypeError를 사용하여 고유 한 오류 개체를 만듭니다.


대부분의 경우 대부분의 오류는 InternalError 또는 SyntaxError와 같은 JavaScript 엔진에서 직접 발생합니다.


const를 다시 할당하려고 할 때 TypeError의 예가 발생합니다.


const name = "Jules";
name = "Caty";

// TypeError: Assignment to constant variable.


SyntaxError의 예는 언어 키워드 철자를 잘못 입력 한 경우입니다.


va x = '33';
// SyntaxError: Unexpected identifier


또는 비동기 함수 외부에서 대기와 같이 잘못된 위치에서 예약 된 키워드를 사용하는 경우 :


function wrong(){
    await 99;
}

wrong();

// SyntaxError: await is only valid in async function


TypeError의 또 다른 예는 페이지에서 존재하지 않는 HTML 요소를 선택할 때 발생합니다.

Uncaught TypeError: button is null


이러한 전통적인 오류 개체 외에도 AggregateError 개체는 곧 JavaScript에 포함될 예정입니다. AggregateError는 나중에 살펴 보겠지만 여러 오류를 함께 래핑하는 데 편리합니다.


이러한 기본 제공 오류 외에도 브라우저에서 다음을 찾을 수 있습니다.


  • DOMException.
  • DOMError, 더 이상 사용되지 않으며 더 이상 사용되지 않습니다.

DOMException은 웹 API와 관련된 오류 계열입니다. 브라우저에서 다음과 같은 어리석은 일을 할 때 발생합니다.


document.body.appendChild(document.cloneNode(true));

결과:


Uncaught DOMException: Node.appendChild: May not add a Document as a child

전체 목록은 MDN의 이 페이지를 참조하십시오.


예외 란 무엇입니까? 


대부분의 개발자는 오류와 예외가 같은 것이라고 생각합니다. 실제로 오류 개체는 throw 될 때만 예외가 됩니다.


JavaScript에서 예외를 발생 시키기 위해 throw와 error 객체를 사용합니다.


const wrongType = TypeError("Wrong type given, expected number");

throw wrongType;


짧은 형식이 더 일반적이며 대부분의 코드베이스에서 다음을 찾을 수 있습니다.


throw TypeError("Wrong type given, expected number");

또는

throw new TypeError("Wrong type given, expected number");


함수 또는 조건부 블록 외부에서 예외를 던질 가능성은 거의 없습니다. 대신 다음 예를 고려하십시오.

function toUppercase(string) {
  if (typeof string !== "string") {
    throw TypeError("Wrong type given, expected a string");
  }

  return string.toUpperCase();
}


여기서 우리는 함수 인수가 문자열인지 확인합니다. 그렇지 않으면 예외가 발생합니다.


기술적으로, 오류 객체뿐만 아니라 JavaScript에서 무엇이든 던질 수 있습니다.


throw Symbol();
throw 33;
throw "Error!";
throw null;


그러나 이러한 것을 피하는 것이 좋습니다. 항상 기본이 아닌 적절한 오류 개체를 던집니다.


이렇게 하면 코드베이스 전체에서 오류 처리를 일관되게 유지할 수 있습니다. 다른 팀 구성원은 항상 오류 개체의 error.message 또는 error.stack에 액세스 할 수 있습니다.


예외가 발생하면 어떻게 됩니까? 


외는 엘리베이터가 올라가는 것과 같습니다. 한 번 던지면 어딘가에 걸리지 않는 한 프로그램 스택에서 거품이 일어납니다.


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


function toUppercase(string) {
  if (typeof string !== "string") {
    throw TypeError("Wrong type given, expected a string");
  }

  return string.toUpperCase();
}

toUppercase(4);


이 코드를 브라우저 또는 Node.js에서 실행하면 프로그램이 중지되고 오류를 보고 합니다.


Uncaught TypeError: Wrong type given, expected a string
    toUppercase http://localhost:5000/index.js:3
    <anonymous> http://localhost:5000/index.js:9


또한 오류가 발생한 정확한 줄을 볼 수 있습니다.


이 보고서는 스택 추적이며 코드의 문제를 추적하는 데 유용합니다.


스택 추적은 아래에서 위로 이동합니다. 그래서 여기 :


    toUppercase http://localhost:5000/index.js:3
    <anonymous> http://localhost:5000/index.js:9


우리는 말할 수 있다:

  • 프로그램의 9 번째 줄에 toUppercase라고 하는 것
  • toUppercase가 3 행에서 폭발했습니다.


브라우저의 콘솔에서 이 스택 추적을 보는 것 외에도 오류 개체의 스택 속성에서 액세스 할 수 있습니다.


예외가 포착되지 않으면, 즉 프로그래머가 예외를 포착하기 위해 아무 작업도 하지 않으면 프로그램이 중단됩니다.


코드에서 예외를 포착하는 시기와 위치는 특정 사용 사례에 따라 다릅니다.


예를 들어 프로그램을 완전히 충돌 시키기 위해 스택에 예외를 전파 할 수 있습니다. 이는 잘못된 데이터로 작업하는 것보다 프로그램을 중지하는 것이 더 안전 할 때 치명적인 오류에 대해 발생할 수 있습니다.


기본 사항을 소개 했으므로 이제 동기 및 비동기 JavaScript 코드 모두에서 오류 및 예외 처리에 대해 살펴 보겠습니다.


동기 오류 처리 


동기 코드는 대부분 간단하므로 오류 처리가 가능합니다.


일반 함수에 대한 오류 처리 


동기 코드는 작성된 순서대로 실행됩니다. 이전 예를 다시 살펴 보겠습니다.


function toUppercase(string) {
  if (typeof string !== "string") {
    throw TypeError("Wrong type given, expected a string");
  }

  return string.toUpperCase();
}

toUppercase(4);

여기서 엔진은 toUppercase를 호출하고 실행합니다. 모두 동시에 발생합니다. 이러한 동기 함수에서 발생하는 예외를 포착하기 위해 try / catch / finally를 사용할 수 있습니다.


try {
  toUppercase(4);
} catch (error) {
  console.error(error.message);
  // or log remotely
} finally {
  // clean up
}


일반적으로 행복한 경로 또는 잠재적으로 발생할 수 있는 함수 호출을 처리해보십시오.


대신 실제 예외를 캡처합니다. 우리가 검사 할 수 있는 오류 객체를 수신합니다 (그리고 프로덕션의 일부 로거에 원격으로 보낼 수 있습니다).


반면에 finally 문은 함수의 결과에 관계없이 실행됩니다. 실패 또는 성공 여부에 관계없이 finally 안의 모든 코드가 실행됩니다.


기억하십시오 : try / catch / finally는 동기식 구조입니다. 이제 비동기 코드에서 발생하는 예외를 포착하는 방법이 있습니다.


생성기 함수에 대한 오류 처리 


JavaScript의 생성기 함수는 특수한 유형의 함수입니다.


내부 범위와 소비자 간의 양방향 통신 채널을 제공하는 것 외에는 마음대로 일시 중지하고 다시 시작할 수 있습니다.


생성기 함수를 만들기 위해 function 키워드 뒤에 별표 *를 넣습니다.


function* generate() {
//
}


함수 내에서 yield를 사용하여 값을 반환 할 수 있습니다.


function* generate() {
  yield 33;
  yield 99;
}


생성기 함수의 반환 값은 반복기 객체입니다. 생성기에서 값을 가져 오기 위해 두 가지 접근 방식을 사용할 수 있습니다.


  • 반복기 객체에서 next ()를 호출합니다.
  • for ... of로 반복합니다.

예를 들어 생성기에서 값을 얻으려면 다음을 수행 할 수 있습니다.


function* generate() {
  yield 33;
  yield 99;
}

const go = generate();


성기 함수를 호출하면 반복기 객체가 됩니다.


이제부터 go.next ()를 호출하여 실행을 진행할 수 있습니다.

function* generate() {
  yield 33;
  yield 99;
}

const go = generate();

const firstStep = go.next().value; // 33
const secondStep = go.next().value; // 99


생성기는 또한 다른 방식으로 작동합니다. 호출자로부터 값과 예외를 다시 받을 수 있습니다.


next () 외에도 생성기에서 반환 된 반복기 객체에는 throw () 메서드가 있습니다.


이 방법을 사용하면 생성기에 예외를 삽입하여 프로그램을 중지 할 수 있습니다.


function* generate() {
  yield 33;
  yield 99;
}

const go = generate();

const firstStep = go.next().value; // 33

go.throw(Error("Tired of iterating!"));

const secondStep = go.next().value; // never reached


이러한 오류를 포착하려면 try / catch를 사용하여 생성기 내부의 코드를 래핑합니다 (필요한 경우 마지막으로).


function* generate() {
  try {
    yield 33;
    yield 99;
  } catch (error) {
    console.error(error.message);
  }
}

생성기 함수는 외부로 예외를 던질 수도 있습니다. 이러한 예외를 포착하는 메커니즘은 동기 예외를 포착하는 것과 동일합니다 : try / catch / finally.


다음은 for ... of를 사용하여 외부에서 사용되는 생성기 함수의 예입니다.

function* generate() {
  yield 33;
  yield 99;
  throw Error("Tired of iterating!");
}

try {
  for (const value of generate()) {
    console.log(value);
  }
} catch (error) {
  console.error(error.message);
}

/* Output:
33
99
Tired of iterating!
*/


여기서 우리는 try 블록 내에서 행복한 경로를 반복합니다. 예외가 발생하면 catch로 중지합니다.


비동기 오류 처리 


JavaScript는 본질적으로 동기식이며 단일 스레드 언어입니다.


브라우저 엔진과 같은 호스트 환경은 외부 시스템과 상호 작용하고 I / O 바운드 작업을 처리하기 위해 여러 웹 API로 JavaScript를 강화합니다.


브라우저의 비동기 성의 예로는 시간 초과, 이벤트, 약속이 있습니다.


비동기 세계에서 오류 처리는 동기식과 다릅니다.


몇 가지 예를 살펴 보겠습니다.


타이머 오류 처리 


JavaScript를 사용한 탐색의 시작 부분에서 try / catch / finally에 대해 배운 후에는 코드 블록에 배치하고 싶을 수 있습니다.


다음 스니펫을 고려하십시오.


function failAfterOneSecond() {
  setTimeout(() => {
    throw Error("Something went wrong!");
  }, 1000);
}

이 함수는 약 1 초 후에 발생합니다. 이 예외를 처리하는 올바른 방법은 무엇입니까?


다음 예제는 작동하지 않습니다.


function failAfterOneSecond() {
  setTimeout(() => {
    throw Error("Something went wrong!");
  }, 1000);
}

try {
  failAfterOneSecond();
} catch (error) {
  console.error(error.message);
}

우리가 말했듯이 try / catch는 동기식입니다. 반면에 타이머 용 브라우저 API 인 setTimeout이 있습니다.


setTimeout에 전달 된 콜백이 실행될 때까지 try / catch가 사라졌습니다. 예외를 캡처 하지 못했기 때문에 프로그램이 중단됩니다.



그들은 두 가지 다른 트랙을 여행합니다.

Track A: --> try/catch
Track B: --> setTimeout --> callback --> throw

프로그램 충돌을 원하지 않는 경우 오류를 올바르게 처리하려면 setTimeout에 대한 콜백 내에서 try / catch를 이동해야 합니다.


그러나 이 접근 방식은 대부분의 경우 그다지 의미가 없습니다. 나중에 살펴 보겠지만 Promises를 사용한 비동기 오류 처리는 더 나은 인체 공학적 기능을 제공합니다.


이벤트에 대한 오류 처리 


Document Object Model의 HTML 노드는 브라우저의 모든 이벤트 이미 터의 공통 조상 인 EventTarget에 연결됩니다.


즉, 페이지의 모든 HTML 요소에서 이벤트를 수신 할 수 있습니다.


(Node.js는 향후 릴리스에서 EventTarget을 지원합니다).


DOM 이벤트에 대한 오류 처리 메커니즘은 비동기 웹 API의 동일한 체계를 따릅니다.


다음 예를 고려하십시오.


const button = document.querySelector("button");

button.addEventListener("click", function() {
  throw Error("Can't touch this button!");
});


여기에서 버튼을 클릭하자마자 예외가 발생합니다. 어떻게 잡을까요? 이 패턴은 작동하지 않으며 프로그램 충돌을 방지하지 않습니다.


const button = document.querySelector("button");

try {
  button.addEventListener("click", function() {
    throw Error("Can't touch this button!");
  });
} catch (error) {
  console.error(error.message);
}


setTimeout을 사용한 이전 예제와 마찬가지로 addEventListener에 전달 된 모든 콜백은 비동기 적으로 실행됩니다.


Track A: --> try/catch
Track B: --> addEventListener --> callback --> throw


프로그램 충돌을 원하지 않는 경우 오류를 올바르게 처리하려면 addEventListener에 대한 콜백 내에서 try / catch를 이동해야 합니다.


그러나 다시 말하지만, 이렇게 하는 데는 별 가치가 없습니다.


setTimeout과 마찬가지로 비동기 코드 경로에서 발생한 예외는 외부에서 찾을 수 없으며 프로그램이 중단됩니다.


다음 섹션에서는 Promises 및 async / await가 어떻게 비동기 코드에 대한 오류 처리를 쉽게 할 수 있는지 살펴 보겠습니다.


onerror는 어떻습니까? 


HTML 요소에는 onclick, onmouseenter, onchange와 같은 여러 이벤트 핸들러가 있습니다.


onerror도 있지만 던지기 및 친구와는 관련이 없습니다.

onerror 이벤트 핸들러는 <img> 태그 또는 <script>와 같은 HTML 요소가 존재하지 않는 리소스에 도달 할 때마다 실행됩니다.


다음 예를 고려하십시오.


// omitted
<body>
<img src="nowhere-to-be-found.png" alt="So empty!">
</body>
// omitted


리소스가 없거나 존재하지 않는 HTML 문서를 방문하면 브라우저의 콘솔에 오류가 기록됩니다.


GET http://localhost:5000/nowhere-to-be-found.png
[HTTP/1.1 404 Not Found 3ms]

JavaScript에서 적절한 이벤트 핸들러를 사용하여 이 오류를 "catch"할 수 있습니다.


const image = document.querySelector("img");

image.onerror = function(event) {
  console.log(event);
};


또는 더 나은 :


const image = document.querySelector("img");

image.addEventListener("error", function(event) {
  console.log(event);
});


이 패턴은 누락 된 이미지 또는 스크립트 대신 대체 리소스를 로드 하는 데 유용합니다.


하지만 기억하세요 : onerror, throw 또는 try / catch와는 아무 관련이 없습니다.


Promise로 오류 처리 


Promise를 사용한 오류 처리를 설명하기 위해 원래 예제 중 하나를 "약속"할 것입니다. 다음 기능을 조정합니다.


function toUppercase(string) {
  if (typeof string !== "string") {
    throw TypeError("Wrong type given, expected a string");
  }

  return string.toUpperCase();
}

toUppercase(4);


간단한 문자열이나 예외를 반환하는 대신 Promise.reject와 Promise.resolve를 사용하여 오류와 성공을 처리합니다.


function toUppercase(string) {
  if (typeof string !== "string") {
    return Promise.reject(TypeError("Wrong type given, expected a string"));
  }

  const result = string.toUpperCase();

  return Promise.resolve(result);
}

(기술적으로 이 코드에는 비동기식이 없지만 요점을 설명하는 데 도움이 됩니다.)


이제 함수가 "약속"되었으므로 결과를 사용하기 위해 첨부하고 거부 된 Promise를 처리하기 위해 catch 할 수 있습니다.


toUppercase(99)
  .then(result => result)
  .catch(error => console.error(error.message));

이 코드는 다음을 기록합니다.


Wrong type given, expected a string


Promise 영역에서 catch는 오류 처리를 위한 구성입니다.


catch 및 then 우리는 try / catch의 finally와 비슷합니다.


동기식 "상대적"인 Promise는 Promise 결과에 관계없이 마침내 실행됩니다.

toUppercase(99)
  .then(result => result)
  .catch(error => console.error(error.message))
  .finally(() => console.log("Run baby, run"));

then / catch / finally에 전달 된 모든 콜백은 Microtask 큐에 의해 비동기 적으로 처리된다는 점을 항상 명심하십시오. 이벤트 및 타이머와 같은 매크로 작업보다 우선 순위가 높은 마이크로 작업입니다.


Promise, error, and throw 


Promise를 거부 할 때 모범 사례로 오류 개체를 제공하는 것이 편리합니다.


Promise.reject(TypeError("Wrong type given, expected a string"));


이렇게 하면 코드베이스 전체에서 오류 처리를 일관되게 유지할 수 있습니다. 다른 팀 구성원은 항상 error.message에 액세스 할 수 있으며 더 중요한 것은 스택 추적을 검사 할 수 있습니다.


Promise.reject 외에도 예외를 throw하여 Promise 체인을 종료 할 수 있습니다.


다음 예를 고려하십시오.


Promise.resolve("A string").then(value => {
  if (typeof value === "string") {
    throw TypeError("Expected a number!");
  }
});


Promise를 끈으로 해결하면 즉시 체인이 끊어집니다.


예외 전파를 중지하려면 평소와 같이 catch를 사용합니다.


Promise.resolve("A string")
  .then(value => {
    if (typeof value === "string") {
      throw TypeError("Expected a number!");
    }
  })
  .catch(reason => console.log(reason.message));


이 패턴은 오류를 검색 할 때 응답 개체를 확인하는 가져 오기에서 일반적입니다.


fetch("https://example-dev/api/")
  .then(response => {
    if (!response.ok) {
      throw Error(response.statusText);
    }

    return response.json();
  })
  .then(json => console.log(json));

여기서 예외는 catch로 가로 챌 수 있습니다. 실패하거나 거기에서 잡지 않기로 결정하면 예외가 스택에서 자유롭게 버블링 됩니다.


이것은 나쁘지 않지만 다른 환경은 포착되지 않은 거부에 다르게 반응합니다.


예를 들어 Node.js는 Promise 거부가 처리되지 않은 모든 프로그램을 중단 시킬 것입니다.


DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.


댓글목록 0

등록된 댓글이 없습니다.

웹학교 로고

온라인 코딩학교

코리아뉴스 2001 - , All right reserved.