웹 프론트엔드 JS 튜토리얼 JavaScript 예외 처리 상세 설명_javascript 기술

JavaScript 예외 처리 상세 설명_javascript 기술

May 16, 2016 pm 04:15 PM
javascript 예외 처리

프론트엔드 엔지니어들은 모두 JavaScript에 기본적인 예외 처리 기능이 있다는 것을 알고 있습니다. new Error()를 던질 수 있고, API를 호출할 때 오류가 발생하면 브라우저도 예외를 던질 것입니다. 하지만 대부분의 프론트엔드 엔지니어들은 이러한 비정상적인 정보 수집을 고려한 적이 없는 것으로 추정됩니다

어쨌든 새로 고침 후에도 JavaScript 오류가 다시 나타나지 않는 한 사용자는 새로 고침을 통해 문제를 해결할 수 있으며 브라우저는 충돌이 발생하지 않은 것처럼 행동합니다. 이 가정은 단일 페이지 앱이 대중화되기 전에는 사실이었습니다. 현재 단일 페이지 앱의 상태는 일정 기간 동안 실행된 후 매우 복잡해집니다. 사용자가 여기에 도착하기 전에 여러 가지 입력 작업을 수행했을 수 있습니다. 새로 고쳐진다고 하면 새로 고쳐야 할까요? 이전 작업을 완전히 다시 수행해야 하는 것 아닌가요? 따라서 이러한 예외 정보를 캡처하고 분석한 다음 사용자 경험에 영향을 주지 않도록 코드를 수정할 수 있습니다.

예외를 잡는 방법

우리는 자체적으로 새로운 Throw Error()를 작성했습니다. 물론 우리는 throw가 어디에 기록되었는지 정확히 알고 있기 때문에 원할 경우 이를 잡을 수 있습니다. 그러나 브라우저 API를 호출할 때 발생하는 예외는 반드시 잡기 쉬운 것은 아닙니다. 일부 API는 예외를 발생시키도록 표준에 작성되어 있으며, 일부 API는 구현 차이 또는 결함으로 인해 개별 브라우저에서만 발생합니다. 전자의 경우 try-catch를 통해 이를 포착할 수도 있습니다. 후자의 경우 전역 예외를 수신한 다음 이를 포착해야 합니다.

시도

일부 브라우저 API가 예외를 발생시키는 것으로 알려진 경우 전체 프로그램이 오류로 인해 잘못된 상태로 들어가는 것을 방지하기 위해 호출을 try-catch에 넣어야 합니다. 예를 들어, window.localStorage는 데이터 쓰기가 용량 제한을 초과하면 예외를 발생시킵니다. 이는 Safari의 개인 탐색 모드에서도 마찬가지입니다.

코드 복사 코드는 다음과 같습니다.

시도해보세요 {
localStorage.setItem('date', Date.now());
} 잡기(오류) {
보고오류(오류);
}


try-catch의 또 다른 일반적인 사용 사례는 콜백입니다. 콜백 함수의 코드는 우리가 통제할 수 없기 때문에 코드의 품질이나 예외를 발생시키는 다른 API가 호출되는지 여부에 대해 알 수 없습니다. 콜백을 호출한 후 다른 코드가 콜백 오류로 인해 실행되지 않는 것을 방지하려면 콜백을 try-catch에 다시 넣어야 합니다.

코드 복사 코드는 다음과 같습니다.

Listeners.forEach(함수(리스너) {
시도해보세요 {
리스너();
} 잡기(오류) {
보고오류(오류);
}
});


window.onerror

try-catch가 적용되지 않는 영역의 경우 예외가 발생하면 window.onerror를 통해서만 catch할 수 있습니다.

코드 복사 코드는 다음과 같습니다.

window.onerror =
함수(errorMessage, scriptURI, lineNumber) {
보고오류({
메시지: errorMessage,
스크립트: scriptURI,
줄: 줄번호
});
}


영리하게 행동하지 않도록 주의하고 window.addEventListener 또는 window.attachEvent를 사용하여 window.onerror를 수신하세요. 많은 브라우저에서는 window.onerror만 구현하거나 window.onerror 구현만 표준입니다. 표준 초안에서도 window.onerror를 정의하고 있다는 점을 고려하면 그냥 window.onerror를 사용해도 됩니다.

속성 상실

캡처된 예외를 수집한 다음 쿼리 및 분석을 위해 일괄적으로 서버 측 저장소로 보내는 reportError 함수가 있다고 가정해 보겠습니다. 더 유용한 정보에는 오류 유형(이름), 오류 메시지(메시지), 스크립트 파일 주소(script), 줄 번호(line), 열 번호(column) 및 스택 추적(stack)이 포함됩니다. try-catch를 통해 예외가 포착되면 이 정보는 Error 개체(주요 브라우저에서 지원됨)에 있으므로 reportError도 이 정보를 수집할 수 있습니다. 하지만 window.onerror를 통해 캡처하면 이 이벤트 함수에는 3개의 매개변수만 있으므로 이 3개의 매개변수에 대한 예상치 못한 정보가 손실된다는 것을 우리 모두 알고 있습니다.

직렬화된 메시지

Error 객체가 스스로 생성된 경우 error.message는 우리가 제어합니다. 기본적으로 우리가 error.message에 무엇을 입력하든 window.onerror의 첫 번째 매개변수(메시지)가 됩니다. (브라우저는 실제로 'Uncaught Error:' 접두사를 추가하는 등 약간의 수정을 합니다.) 따라서 우리가 관심 있는 속성(예: JSON.Stringify)을 직렬화하고 이를 error.message에 저장한 다음 읽을 수 있습니다. window.onerror에서 꺼내서 역직렬화하세요. 물론 이는 우리가 직접 생성한 Error 개체로 제한됩니다.

다섯 번째 매개변수

브라우저 제조업체도 window.onerror를 사용할 때 사람들이 직면하는 한계를 알고 있기 때문에 window.onerror에 새로운 매개변수를 추가하기 시작했습니다. 행 번호만 있고 열 번호가 없는 것을 고려하여 IE는 먼저 열 번호를 추가하고 이를 네 번째 매개 변수에 넣습니다. 그러나 모든 사람들은 완전한 스택을 얻을 수 있는지에 대해 더 관심을 갖고 있으므로 Firefox는 스택을 다섯 번째 매개 변수에 넣는 것이 더 나을 것이라고 말했습니다. 하지만 Chrome에서는 전체 Error 개체를 다섯 번째 매개변수에 넣는 것이 더 낫다고 말했습니다. 맞춤 속성을 포함하여 원하는 모든 속성을 읽을 수 있습니다. 결과적으로 Chrome은 더 빠르게 움직이고 Chrome 30에서 새로운 window.onerror 서명을 구현하여 이에 따라 표준 초안이 작성되었습니다.

코드 복사 코드는 다음과 같습니다.

window.onerror = 함수(
오류 메시지,
스크립트URI,
라인번호,
열번호,
오류
) {
if (오류) {
보고오류(오류);
} 그 밖의 {
보고오류({
메시지: errorMessage,
스크립트: scriptURI,
줄: 줄번호,
열: 열번호
});
}
}


속성 정규화

앞서 논의한 Error 개체 속성의 이름은 Chrome의 명명 방법을 기반으로 합니다. 그러나 브라우저마다 Error 개체 속성의 이름을 다르게 지정합니다. 예를 들어 스크립트 파일 주소는 Chrome에서는 script라고 부르지만 Firefox에서는 filename이라고 합니다. . 따라서 Error 객체를 정규화하는, 즉 서로 다른 속성 이름을 통합된 속성 이름에 매핑하는 특수 함수도 필요합니다. 구체적인 방법은 이 글을 참고하세요. 브라우저 구현이 업데이트되더라도 이러한 매핑 테이블을 수동으로 유지 관리하는 것은 그리 어렵지 않습니다.

스택 추적 형식과 유사합니다. 이 속성은 예외 정보 스택을 일반 텍스트 형식으로 저장합니다. 각 브라우저에서 사용하는 텍스트 형식이 다르기 때문에 일반 텍스트에서 각 프레임의 기능을 추출하려면 정규식을 수동으로 유지해야 합니다. 식별자), 파일(스크립트), 줄 번호(line) 및 열 번호(열)입니다.

보안 제한

'스크립트 오류' 메시지와 함께 오류가 발생했다면 제가 말하는 내용을 이해하실 것입니다. 이는 실제로 다른 출처의 스크립트 파일에 대한 브라우저 제한 사항입니다. 이러한 보안 제한의 이유는 사용자가 로그인한 후 온라인 은행에서 반환한 HTML이 익명 사용자가 본 HTML과 다르다고 가정하면 제3자 웹사이트에서 온라인 은행의 URI를 스크립트에 넣을 수 있기 때문입니다. src 속성. 물론 HTML은 JS로 구문 분석할 수 없으므로 브라우저에서는 예외가 발생하며, 타사 웹사이트에서는 예외 위치를 구문 분석하여 사용자가 로그인했는지 여부를 확인할 수 있습니다. 이러한 이유로 브라우저는 '스크립트 오류'와 같은 변경되지 않은 메시지가 하나만 남고 다른 모든 속성이 사라질 때까지 다양한 소스의 스크립트 파일에서 발생하는 모든 예외를 필터링합니다.

특정 규모의 웹사이트의 경우 스크립트 파일이 다양한 소스의 CDN에 배치되는 것이 일반적입니다. 이제 자신만의 작은 웹사이트를 구축하더라도 jQuery 및 Backbone과 같은 일반적인 프레임워크는 공개 CDN의 버전을 직접 참조하여 사용자 다운로드 속도를 높일 수 있습니다. 따라서 이러한 보안 제한은 일부 문제를 야기하여 Chrome 및 Firefox에서 수집한 예외 정보가 쓸모없는 '스크립트 오류'가 되도록 만듭니다.

코르스

이 제한을 우회하려면 스크립트 파일과 페이지 자체의 출처가 동일한지 확인하세요. 그런데 CDN으로 가속되지 않는 서버에 스크립트 파일을 놓으면 사용자의 다운로드 속도가 느려지지 않나요? 한 가지 해결 방법은 계속해서 CDN에 스크립트 파일을 배치하고 XMLHttpRequest를 사용하여 CORS를 통해 콘텐츠를 다시 다운로드한 다음 <script> 태그를 만들어 페이지에 삽입하는 것입니다. 페이지에 포함된 코드는 물론 동일한 소스에서 가져온 것입니다.

간단해 보이지만 구현해야 할 세부 사항이 많습니다. 간단한 예를 사용하려면:

코드 복사 코드는 다음과 같습니다.

<script src="http://cdn.com/step1.js"></script>

(함수 step2() {})();

<script src="http://cdn.com/step3.js"></script>


step1, step2, step3 사이에 종속성이 있는 경우 반드시 이 순서대로 실행해야 하며 그렇지 않으면 오류가 발생할 수 있다는 것을 우리 모두 알고 있습니다. 브라우저는 step1과 step3의 파일을 병렬로 요청할 수 있지만 실행 중에는 순서가 보장됩니다. XMLHttpRequest를 통해 step1과 step3의 파일 내용을 직접 얻는 경우 순서가 올바른지 확인해야 합니다. 또한 step2는 step1이 비차단 방식으로 다운로드될 때 실행될 수 있으므로 step1을 실행하기 전에 step1이 완료될 때까지 기다리도록 수동으로 개입해야 합니다.

웹사이트의 다양한 페이지에 대해 <script> 태그를 생성하는 도구 세트가 이미 있는 경우 이 도구 세트를 조정하여 <script> 태그를 변경해야 합니다.

코드 복사 코드는 다음과 같습니다.


ScheduleRemoteScript('http://cdn.com/step1.js');


ScheduleInlineScript(함수 코드() {
(함수 step2() {})();
});


ScheduleRemoteScript('http://cdn.com/step3.js');



두 가지 함수인 ScheduleRemoteScript와 ScheduleInlineScript를 구현해야 하며, 이 두 함수가 외부 스크립트 파일을 참조하는 첫 번째 <script> 태그 앞에 정의되어 있는지 확인해야 합니다. 그러면 나머지 <script> 태그가 위 형식으로 다시 작성됩니다. 원래 즉시 실행되었던 step2 함수는 더 큰 코드 함수에 배치되었습니다. 코드 함수는 실행되지 않고 단지 컨테이너일 뿐이므로 2단계의 원본 코드를 탈출하지 않고 유지할 수 있지만 즉시 실행되지는 않습니다.

다음으로 주소를 기반으로 ScheduleRemoteScript로 다운로드한 파일 콘텐츠와 ScheduleInlineScript로 직접 얻은 코드가 올바른 순서로 차례로 실행될 수 있도록 완전한 메커니즘을 구현해야 합니다. 여기서는 자세한 코드를 제공하지 않겠습니다. 관심이 있으시면 직접 구현해 보세요.

역행번호 확인

CORS를 통해 콘텐츠를 가져온 다음 페이지에 코드를 삽입하면 보안 제한을 뚫을 수 있지만 줄 번호 충돌이라는 새로운 문제가 발생합니다. 원래는 error.script를 사용하여 고유한 스크립트 파일을 찾을 수 있었고 error.line을 사용하여 고유한 줄 번호를 찾을 수 있었습니다. 이제 페이지에 포함된 코드이므로 여러 개의 <script> 태그를 error.script로 구분할 수 없습니다. 그러나 각 <script> 태그 안의 줄 번호는 1부터 시작합니다. 오류가 있는 소스 코드 위치를 찾는 데 사용됩니다.

줄 번호 충돌을 피하기 위해 각 <script> 태그의 실제 코드에서 사용되는 줄 번호 범위가 서로 겹치지 않도록 일부 줄 번호를 낭비할 수 있습니다. 예를 들어, 각 <script> 태그의 실제 코드가 1000줄을 넘지 않는다고 가정하면 첫 번째 <script> 태그의 코드는 1~1000줄을 차지하고 두 번째 코드는 <script> 태그는 1001~2000행(그 앞에 1000개의 빈 행 삽입)을 차지하고 세 번째 <script> 태그의 코드는 2001~3000행(그 앞에 2000개의 빈 행을 삽입)을 차지합니다. 그런 다음 data-* 속성을 사용하여 쉽게 검색할 수 있도록 이 정보를 기록합니다.

코드 복사 코드는 다음과 같습니다.

<스크립트
data-src="http://cdn.com/step1.js"
데이터-라인-시작="1"
>
// 1단계 코드

<script data-line-start="1001">
// 'n' * 1000
// 2단계 코드

<스크립트
data-src="http://cdn.com/step3.js"
데이터-라인-시작="2001"
>
// 'n' * 2000
// 3단계 코드



이 처리 후 에러의 error.line이 3005라면 실제 error.script는 'http://cdn.com/step3.js', 실제 error.line은 5가 되어야 한다는 뜻이다. 앞서 언급한 reportError 함수에서 이 줄 번호 역방향 검사를 완료할 수 있습니다.

물론 각 스크립트 파일에 1000줄만 있다고 보장할 수 없고 일부 스크립트 파일은 1000줄보다 훨씬 작을 수 있으므로 각 <script> 태그에 1000줄이라는 고정된 범위를 할당할 필요는 없습니다. . 각 <script> 태그에서 사용하는 간격이 겹치지 않는 한 실제 스크립트 줄 수를 기준으로 간격을 할당할 수 있습니다.

crossorigin 속성

물론 다양한 소스의 콘텐츠에 대해 브라우저가 적용하는 보안 제한은 <script> 태그에만 국한되지 않습니다. XMLHttpRequest는 CORS를 통해 이러한 제한을 극복할 수 있는데 왜 태그를 통해 리소스를 직접 참조할 수 없습니까? 물론 이것은 가능합니다.

다른 소스의 스크립트 파일을 참조하는 <script> 태그에 대한 제한은 다른 소스의 이미지 파일을 참조하는 <img>에도 적용됩니다. <img> 태그가 다른 소스에서 나온 경우 <canvas> 그리기에 사용되면 웹사이트가 JavaScript를 통해 다른 소스에서 승인되지 않은 이미지 데이터를 훔칠 수 없게 됩니다. 나중에 <img> 태그는 crossorigin 속성을 도입하여 이 문제를 해결했습니다. crossorigin="anonymous"를 사용하는 경우 익명 CORS와 동일하며 `crossorigin="use-credentials"를 사용하는 경우 인증이 포함된 CORS와 동일합니다.

<img> 태그가 이 작업을 수행할 수 있다면 왜 <script> 태그는 이를 수행할 수 없습니까? 따라서 브라우저 제조업체는 위의 보안 제한 사항을 해결하기 위해 동일한 crossorigin 속성을 <script> 태그에 추가했습니다. Chrome과 Firefox는 현재 아무런 문제 없이 이 속성을 지원합니다. Safari는 crossorigin="anonymous"를 crossorigin="use-credentials"로 처리합니다. 결과적으로 서버가 익명 CORS만 지원하는 경우 Safari는 인증을 실패한 것으로 처리합니다. CDN 서버는 성능상의 이유로 정적 콘텐츠만 반환하도록 설계되었기 때문에 요청에 따라 CORS 인증에 필요한 HTTP 헤더를 동적으로 반환하는 것은 불가능합니다. Safari는 이 기능을 사용하여 위의 문제를 해결할 수 없습니다.

요약

JavaScript 예외 처리는 매우 간단하고 다른 언어와 다를 바 없는 것처럼 보이지만 실제로 모든 예외를 잡아서 속성을 분석하는 것은 그리 쉽지 않습니다. JavaScript 예외를 캡처하는 Google Analytics와 유사한 서비스를 제공하는 일부 타사 서비스가 있지만 세부 사항과 원칙을 이해하려면 여전히 직접 수행해야 합니다.

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

뜨거운 기사 태그

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

C++ 함수 예외 및 멀티스레딩: 동시 환경의 오류 처리 C++ 함수 예외 및 멀티스레딩: 동시 환경의 오류 처리 May 04, 2024 pm 04:42 PM

C++ 함수 예외 및 멀티스레딩: 동시 환경의 오류 처리

C++ 예외 처리는 사용자 정의 오류 처리 루틴을 어떻게 지원합니까? C++ 예외 처리는 사용자 정의 오류 처리 루틴을 어떻게 지원합니까? Jun 05, 2024 pm 12:13 PM

C++ 예외 처리는 사용자 정의 오류 처리 루틴을 어떻게 지원합니까?

Java 함수의 재귀 호출과 예외 처리 간의 관계는 무엇입니까? Java 함수의 재귀 호출과 예외 처리 간의 관계는 무엇입니까? May 03, 2024 pm 06:12 PM

Java 함수의 재귀 호출과 예외 처리 간의 관계는 무엇입니까?

C++ 기술의 예외 처리: 다중 스레드 환경에서 예외를 올바르게 처리하는 방법은 무엇입니까? C++ 기술의 예외 처리: 다중 스레드 환경에서 예외를 올바르게 처리하는 방법은 무엇입니까? May 09, 2024 pm 12:36 PM

C++ 기술의 예외 처리: 다중 스레드 환경에서 예외를 올바르게 처리하는 방법은 무엇입니까?

Java 다중 스레드 환경의 예외 처리 Java 다중 스레드 환경의 예외 처리 May 01, 2024 pm 06:45 PM

Java 다중 스레드 환경의 예외 처리

C++ Lambda 표현식에서 예외를 처리하는 방법은 무엇입니까? C++ Lambda 표현식에서 예외를 처리하는 방법은 무엇입니까? Jun 03, 2024 pm 03:01 PM

C++ Lambda 표현식에서 예외를 처리하는 방법은 무엇입니까?

PHP 예외 처리: 예외 추적을 통해 시스템 동작 이해 PHP 예외 처리: 예외 추적을 통해 시스템 동작 이해 Jun 05, 2024 pm 07:57 PM

PHP 예외 처리: 예외 추적을 통해 시스템 동작 이해

크로스 스레드 C++ 예외를 처리하는 방법은 무엇입니까? 크로스 스레드 C++ 예외를 처리하는 방법은 무엇입니까? Jun 06, 2024 am 10:44 AM

크로스 스레드 C++ 예외를 처리하는 방법은 무엇입니까?

See all articles