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