프론트 엔드 엔지니어는 모두 JavaScript에 기본 예외 처리 기능이 있음을 알고 있습니다. 새로운 오류 ()를 던질 수 있으며 브라우저는 API 오류를 호출 할 때 예외를 던집니다. 그러나 대부분의 프론트 엔드 엔지니어는 이러한 예외 정보 수집을 고려한 적이없는 것으로 추정됩니다.
어쨌든, JavaScript 오류 후 새로 고침이 재현되지 않는 한, 사용자는 새로 고침으로 문제를 해결할 수 있으며 브라우저가 충돌하지 않으며 발생하지 않으면 괜찮습니다. 이 가정은 단일 페이지 앱이 인기를 얻기 전에 사실이었습니다. 현재 단일 페이지 앱은 일정 시간 동안 실행 한 후 매우 복잡합니다. 사용자는 여기에 오기 전에 여러 입력 작업을 수행했을 수 있습니다. 그들이 원한다고 말하면 어떻게 상쾌 할 수 있습니까? 이전 작업을 완전히 재 작업하지 않겠습니까? 따라서 이러한 예외 정보를 캡처하고 분석해야하며 사용자 경험에 영향을 미치지 않도록 코드를 수정할 수 있습니다.
예외를 포착하는 방법
우리는 스스로 새로운 오류를 던졌습니다 (). 우리가 캡처하고 싶다면, 우리는 Throw가 쓰여진 곳을 잘 알고 있기 때문에 확실히 캡처 할 수 있습니다. 그러나 브라우저 API를 호출 할 때 발생하는 예외가 반드시 잡기가 쉽지는 않습니다. 일부 API는 예외가 표준에 던져지고 일부 API는 구현 차이 또는 결함으로 인해 개별 브라우저 만 예외 만 가지고 있다고 말합니다. 전자의 경우 우리는 시도 캐치를 통해 그것을 잡을 수 있습니다. 후자는 전 세계 예외를 듣고 잡아야합니다.
Try-Catch
일부 브라우저 API가 예외를 던지는 것으로 알려져있는 경우, 오류로 인해 불법 상태에 들어가는 전체 프로그램이 불법 상태로 들어가는 것을 피하기 위해 Try-Catch에 전화를 걸어야합니다. 예를 들어, window.localstorage는 API입니다. 쓰기 데이터가 용량 제한을 초과 한 후 예외가 발생하며 Safari의 개인 브라우징 모드에서도 마찬가지입니다.
코드 사본은 다음과 같습니다.
노력하다 {
LocalStorage.setitem ( 'date', date.now ());
} catch (오류) {
리포터 (오류);
}
또 다른 일반적인 Try-Catch 해당 시나리오는 콜백입니다. 콜백 함수의 코드는 통제 할 수 없기 때문에 코드가 얼마나 좋은지, 예외를 제외하고 다른 API가 호출되는지 여부를 알 수 없습니다. 콜백 오류로 인해 콜백을 호출 한 후 다른 코드가 실행되지 않으려면 통화를 다시 시도 캐치로 다시 넣어야합니다.
코드 사본은 다음과 같습니다.
청취자 .foreach (기능 (청취자) {
노력하다 {
경청자();
} catch (오류) {
리포터 (오류);
}
});
Window.onerror
Try-Catch를 다룰 수없는 장소의 경우 예외가 발생하면 Window.onerror를 통해서만 캡처 할 수 있습니다.
코드 사본은 다음과 같습니다.
Window.onerror =
함수 (errormessage, scripturi, linenumber) {
리포터 ({{
메시지 : errormessage,
대본 : Scripturi,
라인 : LineNumber
});
}
영리하지 않고 Window.AdDeventListener 또는 Window.attachevent를 사용하여 Window.onerror를 들어보십시오. 많은 브라우저는 Window.Onerror 또는 Window 만 구현합니다. ONERROR 구현은 표준입니다. 표준 드래프트가 Window.onerror를 정의하는 것을 고려하면 Window.onerror를 사용하면됩니다.
속성 누락
잡힌 예외를 수집 한 후 쿼리 및 분석을 위해 서버 측 스토리지에 배치로 전송하는 리포터 기능이 있다고 가정 해 봅시다. 수집하려는 정보는 무엇입니까? 보다 유용한 정보에는 오류 유형 (이름), 오류 메시지 (메시지), 스크립트 파일 주소 (스크립트), 줄 번호 (줄), 열 번호 (열) 및 스택 추적이 포함됩니다. Try-Catch를 통해 예외가 발생하면 이러한 모든 정보는 오류 개체 (주류 브라우저에서 지원)에 있으므로 Reporterror 도이 정보를 수집 할 수 있습니다. 그러나 Window.onerror를 통해 캡처되면이 이벤트 기능에는 3 개의 매개 변수 만 있으므로이 3 개의 매개 변수의 예상치 못한 정보가 손실됩니다.
메시지 직렬화
오류 객체가 스스로 생성되면 오류. 메신저는 당사에 의해 제어됩니다. 기본적으로, 우리가 오류에 넣은 것. message, 그리고 Window.onerror의 첫 번째 매개 변수 (메시지)가 될 것입니다. (브라우저는 실제로 'ught error :'prefix를 추가하는 것과 같이 약간 수정됩니다.) 따라서 우리는 우리가 우려하는 속성을 직렬화하고 (예 : json.stringify) 오류에 저장 한 다음 Window.onerror를 읽어서 그것들을 읽을 수 있습니다. 물론 이것은 우리가 만든 오류 객체로 제한됩니다.
다섯 번째 매개 변수
브라우저 제조업체는 또한 Window.onerror를 사용할 때 사람들이 적용하는 제한 사항을 알고 있으므로 Window.onerror에 새 매개 변수를 추가하기 시작합니다. 행 번호와 열 숫자만이 매우 대칭적인 것으로 보인다는 점을 고려하면 먼저 열 숫자를 추가하여 네 번째 매개 변수에 배치했습니다. 그러나 모든 사람이 더 염려하는 것은 완전한 스택을 얻을 수 있는지 여부입니다. 그러나 Chrome은 전체 오류 객체를 다섯 번째 매개 변수에 넣는 것이 좋습니다. 사용자 정의 속성을 포함하여 읽을 속성. 결과적으로 Chrome이 빠르기 때문에 새로운 창이 더 빠르기 때문에 Crome 30에서 정기 서명이 구현되어 다음과 같은 표준 초안을 작성했습니다.
코드 사본은 다음과 같습니다.
Window.onerror = 함수 (
errormessage,
Scripturi,
Linenumber,
칼럼 번호,
오류
) {
if (오류) {
리포터 (오류);
} 또 다른 {
리포터 ({{
메시지 : errormessage,
대본 : Scripturi,
라인 : LineNumber,
열 : 칼럼 번호
});
}
}
속성의 규칙 성
이전에 논의한 오류 객체 속성의 이름은 크롬 이름 지정 방법을 기반으로합니다. 그러나 다른 브라우저는 오류 객체 속성을 다르게 지정합니다. 예를 들어, 스크립트 파일 주소는 Chrome에서 스크립트라고하지만 Firefox에서는 파일 이름입니다. 따라서 오류 객체를 정규화하려면 특수 함수가 필요합니다. 즉 다른 속성 이름을 통합 된 속성 이름에 매핑합니다. 특정 관행은이 기사를 참조하십시오. 브라우저 구현이 업데이트되지만 누구나 그러한 매핑 테이블을 유지하기가 어렵지 않습니다.
스택 추적 형식도 비슷합니다. 이 속성은 일반 텍스트로 발생할 때 예외의 스택 정보를 저장합니다. 각 브라우저에서 사용하는 텍스트 형식은 다르므로 일반 텍스트에서 각 프레임의 함수 이름 (식별자), 파일 (스크립트), 열 번호 (열)를 추출하기 위해 정규 표현식을 유지해야합니다.
보안 제한
또한 '스크립트 오류'에 오류가 발생한 경우, 내가 말하는 내용을 이해할 수 있습니다. 이것은 실제로 다른 소스의 스크립트 파일에 대한 브라우저의 한계입니다. 이 보안 제한의 이유는 다음과 같습니다. 로그인 한 후 온라인 은행가가 반환 한 HTML이 익명 사용자가 보이는 HTML과 다르다고 가정 해 봅시다. 타사 웹 사이트는이 온라인 은행의 URI를 Script.SRC 속성에 넣을 수 있습니다. 물론 HTML은 JS로 구문 분석 할 수 없으므로 브라우저는 예외를 던지고이 타사 웹 사이트는 예외의 위치를 분석하여 사용자가 로그인되는지 여부를 결정할 수 있습니다. 이러한 이유로 브라우저는 다른 소스 스크립트 파일에 의해 던져진 모든 예외를 필터링하여 '스크립트 오류'와 같은 변경되지 않은 메시지 만 남겨두고 다른 모든 속성은 사라집니다.
특정 규모의 웹 사이트의 경우 스크립트 파일이 CDN에 배치되는 것이 일반적이며 다른 소스가 배치됩니다. 이제 작은 웹 사이트를 직접 구축하더라도 JQuery 및 Backbone과 같은 일반적인 프레임 워크는 공개 CDN의 버전을 직접 참조하여 사용자 다운로드 속도를 높일 수 있습니다. 따라서이 보안 제한으로 인해 약간의 문제가 발생하여 Chrome 및 Firefox에서 수집 한 예외 정보가 쓸모없는 '스크립트 오류'가됩니다.
코스
이 제한을 우회하려면 스크립트 파일과 페이지 자체가 동일한 원점인지 확인하십시오. 그러나 사용자의 다운로드 속도를 늦추기 위해 CDN에 의해 가속되지 않은 서버에 스크립트 파일을 배치하지 않습니까? 한 가지 해결책은 Script 파일을 CDN에 계속 배치하고 XMLHTTPREQUEST를 사용하여 CORS를 통해 컨텐츠를 다시 다운로드 한 다음 <Script> 태그를 작성하여 페이지에 주입하는 것입니다. 페이지에 내장 된 코드는 물론 동일한 원점입니다.
이것은 간단하지만 구현해야 할 세부 사항이 많이 있습니다. 간단한 예를 들기 위해 :
코드 사본은 다음과 같습니다.
<script src = "http://cdn.com/step1.js"> </script>
<cript>
(함수 step2 () {}) ();
</스크립트>
<script src = "http://cdn.com/step3.js"> </script>
우리는 모두 1, step2 및 step3에 종속성이 있으면이 순서로 엄격하게 실행되어야한다는 것을 알고 있습니다. 그렇지 않으면 오류가 발생할 수 있습니다. 브라우저는 STEP1 및 STEP3 파일을 병렬로 요청할 수 있지만 실행되면 주문이 보장됩니다. xmlhttprequest를 사용하여 STEP1 및 STEP3의 파일 내용을 얻는 경우 직접 올바른 순서를 보장해야합니다. 또한 STEP2를 잊지 마십시오. STEP2는 STEP1을 차단 형식으로 다운로드 할 때 실행할 수 있으므로 STEP2를 방해하고 실행하기 전에 STEP1이 완료 될 때까지 기다려야합니다.
웹 사이트의 다른 페이지에 대한 <cript> 태그를 생성 할 수있는 전체 도구 세트가 이미 있다면 <cript> 태그를 변경하기 위해이 도구 세트를 조정해야합니다.
코드 사본은 다음과 같습니다.
<cript>
scheduleremotescript ( 'http://cdn.com/step1.js');
</스크립트>
<cript>
ScheduleInLinescript (function code () {
(함수 step2 () {}) ();
});
</스크립트>
<cript>
scheduleremotescript ( 'http://cdn.com/step3.js');
</스크립트>
두 가지 함수 scheduleremotescript 및 scheduleInlineScript를 구현하고 외부 스크립트 파일을 참조하는 첫 번째 <cript> 태그 앞에 정의되도록하고 나머지 <Script> 태그가 위 형식으로 다시 작성됩니다. 즉시 실행 된 STEP2 함수는 더 큰 코드 함수에 배치되었습니다. 코드 함수는 실행되지 않고 컨테이너 일 뿐이므로 원래 Step2 코드를 탈출하지 않고 유지할 수 있지만 즉시 실행되지 않습니다.
다음으로, 주소를 기반으로 SchedulerEmotescript와 SchedareInlineScript에 의해 직접 얻은 코드를 올바른 순서로 하나씩 실행할 수 있도록 완전한 메커니즘을 구현해야합니다. 나는 여기에 자세한 코드를주지 않을 것입니다. 관심이 있으시면 직접 구현할 수 있습니다.
줄 번호 검사
CORS를 통해 컨텐츠를 가져 와서 페이지에 코드를 주입하면 보안 제한을 뚫을 수 있지만 새로운 문제, 즉 줄 번호 충돌이 발생할 수 있습니다. 원래 고유 스크립트 파일은 Error.Script를 통해 위치 할 수 있으며 고유 한 줄 번호는 error.line을 통해 위치 할 수 있습니다. 이제 페이지에 내장 된 모든 코드가 모두 코드이므로 여러 <cript> 태그는 Error.Script로 구별 할 수 없습니다. 그러나 각 <cript> 태그 내부의 줄 번호는 1에서 계산되므로 예외 정보를 사용하여 오류가있는 소스 코드 위치를 찾을 수 없습니다.
줄 번호 충돌을 피하기 위해 각 <cript> 태그에서 실제 코드에서 사용하는 줄 번호 간격이 서로 겹치지 않도록 일부 줄 번호를 낭비 할 수 있습니다. 예를 들어, 각 <cript> 태그의 실제 코드가 1000 줄을 초과하지 않는다고 가정하면 첫 번째 <cript>의 코드가 Line 11000, 두 번째 <cript>의 코드는 10012000을 점유 한 줄 (1000 개의 빈 줄은 이전에 삽입 됨)을 삽입했습니다. 그런 다음 Data-* 속성을 사용 하여이 정보를 쉽게 검색하기 위해이 정보를 기록합니다.
코드 사본은 다음과 같습니다.
<스크립트
data-src = "http://cdn.com/step1.js"
데이터 라인 스타트 = "1"
>
// 1 단계 코드
</스크립트>
<스크립트 데이터 라인 스타트 = "1001">
// '/n' * 1000
// 2 단계 코드
</스크립트>
<스크립트
data-src = "http://cdn.com/step3.js"
데이터 라인 스타트 = "2001"
>
// '/n' * 2000
// 3 단계 코드
</스크립트>
이 처리 후 오류 오류 오류가 3005 인 경우 실제 error.script는 'http://cdn.com/step3.js'여야하고 실제 오류는 5 여야 함을 의미합니다. 앞에서 언급 한 리포터 기능 에서이 줄 번호 리버스 확인을 완료 할 수 있습니다.
물론 각 스크립트 파일에 1000 줄만이 있음을 보장 할 수 없으므로 일부 스크립트 파일이 1000 줄보다 상당히 작을 수도 있으므로 각 <cript> 태그에 1000 줄 간격을 고정으로 할당 할 필요가 없습니다. 실제 스크립트 라인 수를 기반으로 간격을 할당 할 수 있습니다. 각 <cript> 태그가 사용하는 간격이 겹치지 않도록하십시오.
Crossorigin 속성
다른 소스의 컨텐츠에 대한 브라우저가 부과하는 보안 제한은 물론 <cript> 태그에 국한되지 않습니다. xmlhttprequest는 CORS를 통해이 제한을 뚫을 수 있으므로 태그를 통해 자원이 직접 참조되는 이유는 무엇입니까? 이것은 확실히 괜찮습니다.
<cript> 태그에 대한 다른 소스 스크립트 파일을 참조하는 제한은 <Img> 태그의 다른 소스 이미지 파일을 참조하는데도 적용됩니다. <Img> 태그가 다른 소스 인 경우 <canvas> 드로잉에 한 번 사용 된 경우 <canvas>는 쓰기 전용 상태가되어 웹 사이트가 JavaScript를 통해 다른 소스에서 무단 이미지 데이터를 훔칠 수 없도록합니다. 나중에 <Img> 태그는 Crossorigin 속성을 도입 하여이 문제를 해결했습니다. Crossorigin = "익명"인 경우 익명 CORS와 동일합니다. Crossorigin = "use-credentials"인 경우 인증 된 CORS와 같습니다.
<Img> 태그가 이것을 할 수 있기 때문에 왜 <cript> 태그가 이것을 할 수 없습니까? 따라서 브라우저 제조업체는 위의 보안 제한을 해결하기 위해 <Script> 태그에 동일한 Crossorigin 속성을 추가했습니다. 이제이 부동산에 대한 Chrome 및 Firefox 지원은 완전히 무료입니다. Safari는 Crossorigin = "익명"을 Crossorigin = "use-credentials"로 취급 할 것이며, 그 결과 서버가 익명 CORS 만 지원하면 Safari가 인증을 실패로 취급합니다. CDN 서버는 성능의 이유로 정적 컨텐츠 만 반환하도록 설계되었으므로 요청에 따라 CORS를 인증하는 데 필요한 HTTP 헤더를 동적으로 반환하는 것은 불가능합니다. Safari는이 기능을 사용하여 위의 문제를 해결할 수없는 것과 같습니다.
요약
JavaScript 예외 처리는 단순 해 보이고 다른 언어와 다르지 않지만 모든 예외를 포착하고 속성을 분석하는 것은 쉽지 않습니다. 이제 일부 타사 서비스는 JavaScript 예외를 포착하는 Google 웹 로그 분석과 같은 서비스를 제공하지만 세부 사항과 원칙을 이해하려면 여전히 직접 수행해야합니다.