[javascript] JavaScript 글로벌 이벤트 메커니즘

모든 정의되지 않은 함수 오류가 발생하고 싶습니다. JavaScript에 전역 오류 처리 기능이 있습니까? 유스 케이스가 정의되지 않은 플래시에서 함수 호출을 포착하고 있습니다.



답변

도움이 되나요?

<script type="text/javascript">
window.onerror = function() {
    alert("Error caught");
};

xxx();
</script>

그래도 플래시 오류를 어떻게 처리하는지 잘 모르겠습니다 …

업데이트 : Opera에서는 작동하지 않지만 지금은 잠자리를 해킹하여 얻을 수있는 것을 확인합니다. 잠자리 해킹에 대한 제안은이 질문에서 나왔습니다.

모방 창. 자바 스크립트를 사용하는 Opera의 오류


답변

처리되지 않은 Javascript 오류를 잡는 방법

다음 window.onerror과 같이 이벤트 핸들러에 이벤트를 지정하십시오 .

<script type="text/javascript">
window.onerror = function(msg, url, line, col, error) {
   // Note that col & error are new to the HTML 5 spec and may not be 
   // supported in every browser.  It worked for me in Chrome.
   var extra = !col ? '' : '\ncolumn: ' + col;
   extra += !error ? '' : '\nerror: ' + error;

   // You can view the information in an alert to see things working like this:
   alert("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);

   // TODO: Report this error via ajax so you can keep track
   //       of what pages have JS issues

   var suppressErrorAlert = true;
   // If you return true, then error alerts (like in older versions of 
   // Internet Explorer) will be suppressed.
   return suppressErrorAlert;
};
</script>

의 반환 값이있는 경우, 코드에 주석으로 window.onerror이다 true다음 브라우저는 경고 대화 상자를 표시 억제해야한다.

언제 window.onerror 이벤트가 발생합니까?

간단히 말해서, 1.) 포착되지 않은 예외가 있거나 2.) 컴파일 시간 오류가 발생하면 이벤트가 발생합니다.

포착되지 않은 예외

  • “일부 메시지”던지기
  • call_something_undefined ();
  • cross_origin_iframe.contentWindow.document; 보안 예외

컴파일 오류

  • <script>{</script>
  • <script>for(;)</script>
  • <script>"oops</script>
  • setTimeout("{", 10);첫 번째 인수를 스크립트로 컴파일하려고 시도합니다.

window.onerror를 지원하는 브라우저

  • 크롬 13+
  • Firefox 6.0 이상
  • Internet Explorer 5.5 이상
  • 오페라 11.60+
  • 사파리 5.1 이상

스크린 샷 :

이것을 테스트 페이지에 추가 한 후 실행되는 위의 오류 코드 예제 :

<script type="text/javascript">
call_something_undefined();
</script>

window.onerror 이벤트에 의해 자세한 오류 정보를 표시하는 Javascript 경고

AJAX 오류보고의 예

var error_data = {
    url: document.location.href,
};

if(error != null) {
    error_data['name'] = error.name; // e.g. ReferenceError
    error_data['message'] = error.line;
    error_data['stack'] = error.stack;
} else {
    error_data['msg'] = msg;
    error_data['filename'] = filename;
    error_data['line'] = line;
    error_data['col'] = col;
}

var xhr = new XMLHttpRequest();

xhr.open('POST', '/ajax/log_javascript_error');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
    if (xhr.status === 200) {
        console.log('JS error logged');
    } else if (xhr.status !== 200) {
        console.error('Failed to log JS error.');
        console.error(xhr);
        console.error(xhr.status);
        console.error(xhr.responseText);
    }
};
xhr.send(JSON.stringify(error_data));

JSFiddle :

https://jsfiddle.net/nzfvm44d/

참고 문헌 :


답변

정교한 오류 처리

오류 처리가 매우 정교하여 오류 자체가 발생할 수있는 경우 이미 “errorHandling-Mode”에 있는지 여부를 나타내는 플래그를 추가하면 유용합니다. 이렇게 :

var appIsHandlingError = false;

window.onerror = function() {
    if (!appIsHandlingError) {
        appIsHandlingError = true;
        handleError();
    }
};

function handleError() {
    // graceful error handling
    // if successful: appIsHandlingError = false;
}

그렇지 않으면 무한 루프에서 자신을 찾을 수 있습니다.


답변

최신 웹 앱에 고급 오류 추적 및 실제 사용자 모니터링을 제공하는 Atatus 를 사용해보십시오 .

https://www.atatus.com/

모든 브라우저에서 합리적으로 완전한 스택 추적을 얻는 방법을 설명하겠습니다.

JavaScript에서 오류 처리

최신 Chrome 및 Opera는 ErrorEvent 및에 대한 HTML 5 초안 사양을 완벽하게 지원합니다 window.onerror. 이 두 브라우저에서 모두를 사용 window.onerror하거나 ‘오류’이벤트에 올바르게 바인딩 할 수 있습니다 .

// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendError(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
    console.log(e.error.message, "from", e.error.stack);
    // You can send data to your server
    // sendError(data);
})

불행히도 Firefox, Safari 및 IE는 여전히 사용 중이며 우리도이를 지원해야합니다. 스택 트레이스를 사용할 수 없으므로window.onerror 없으므로 조금 더 많은 작업을 수행해야합니다.

오류로부터 스택 트레이스를 얻기 위해 할 수있는 유일한 방법은 모든 코드를 try{ }catch(e){ }블록 으로 감싸고 를 보는 것 e.stack입니다. 우리는 wrap이라는 함수를 사용하여 프로세스를 좀 더 쉽게 만들 수 있습니다.이 함수는 함수를 취하고 오류 처리 기능이 좋은 새 함수를 반환합니다.

function wrap(func) {
    // Ensure we only wrap the function once.
    if (!func._wrapped) {
        func._wrapped = function () {
            try{
                func.apply(this, arguments);
            } catch(e) {
                console.log(e.message, "from", e.stack);
                // You can send data to your server
                // sendError(data);
                throw e;
            }
        }
    }
    return func._wrapped;
};

작동합니다. 수동으로 포장하는 모든 기능에는 오류 처리 기능이 우수하지만 대부분의 경우 실제로 자동으로 수행 할 수 있습니다.

addEventListener콜백을 자동으로 감싸도록 전역 정의를 변경하면 try{ }catch(e){ }대부분의 코드 주위에 자동으로 삽입 할 수 있습니다 . 이를 통해 기존 코드는 계속 작동하지만 고품질 예외 추적이 추가됩니다.

var addEventListener = window.EventTarget.prototype.addEventListener;
window.EventTarget.prototype.addEventListener = function (event, callback, bubble) {
    addEventListener.call(this, event, wrap(callback), bubble);
}

또한 removeEventListener계속 작동 하는지 확인해야 합니다. 현재에 대한 인수 addEventListener가 변경 되지 않았기 때문 입니다. 다시 우리는이 문제를 해결해야합니다prototype 객체에서 :

var removeEventListener = window.EventTarget.prototype.removeEventListener;
window.EventTarget.prototype.removeEventListener = function (event, callback, bubble) {
    removeEventListener.call(this, event, callback._wrapped || callback, bubble);
}

오류 데이터를 백엔드로 전송

다음과 같이 이미지 태그를 사용하여 오류 데이터를 보낼 수 있습니다

function sendError(data) {
    var img = newImage(),
        src = 'http://yourserver.com/jserror&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() {
        console.log('success', data);
    };
    img.onerror = img.onabort = function failure() {
        console.error('failure', data);
    };
    img.src = src;
}

면책 조항 : 저는 https://www.atatus.com/ 의 웹 개발자 입니다.


답변

window.onerror가능한 모든 오류에 대한 액세스를 제공하지 않는 것 같습니다 . 특히 다음을 무시합니다.

  1. <img> 로딩 오류 (응답> = 400).
  2. <script> 로딩 오류 (응답> = 400).
  3. 앱에 많은 다른 라이브러리가 있으면 전역 오류가 발생합니다. window.onerror 알 수없는 방식으로 하는 (jquery, angular 등).
  4. 아마도 이것을 탐색 한 후에도 많은 사례가 발생했을 것입니다 (iframe, stack overflow 등).

다음은 이러한 많은 오류를 포착하는 스크립트의 시작입니다. 따라서 개발 중에 앱에보다 강력한 디버깅을 추가 할 수 있습니다.

(function(){

/**
 * Capture error data for debugging in web console.
 */

var captures = [];

/**
 * Wait until `window.onload`, so any external scripts
 * you might load have a chance to set their own error handlers,
 * which we don't want to override.
 */

window.addEventListener('load', onload);

/**
 * Custom global function to standardize
 * window.onerror so it works like you'd think.
 *
 * @see http://www.quirksmode.org/dom/events/error.html
 */

window.onanyerror = window.onanyerror || onanyerrorx;

/**
 * Hook up all error handlers after window loads.
 */

function onload() {
  handleGlobal();
  handleXMLHttp();
  handleImage();
  handleScript();
  handleEvents();
}

/**
 * Handle global window events.
 */

function handleGlobal() {
  var onerrorx = window.onerror;
  window.addEventListener('error', onerror);

  function onerror(msg, url, line, col, error) {
    window.onanyerror.apply(this, arguments);
    if (onerrorx) return onerrorx.apply(null, arguments);
  }
}

/**
 * Handle ajax request errors.
 */

function handleXMLHttp() {
  var sendx = XMLHttpRequest.prototype.send;
  window.XMLHttpRequest.prototype.send = function(){
    handleAsync(this);
    return sendx.apply(this, arguments);
  };
}

/**
 * Handle image errors.
 */

function handleImage() {
  var ImageOriginal = window.Image;
  window.Image = ImageOverride;

  /**
   * New `Image` constructor. Might cause some problems,
   * but not sure yet. This is at least a start, and works on chrome.
   */

  function ImageOverride() {
    var img = new ImageOriginal;
    onnext(function(){ handleAsync(img); });
    return img;
  }
}

/**
 * Handle script errors.
 */

function handleScript() {
  var HTMLScriptElementOriginal = window.HTMLScriptElement;
  window.HTMLScriptElement = HTMLScriptElementOverride;

  /**
   * New `HTMLScriptElement` constructor.
   *
   * Allows us to globally override onload.
   * Not ideal to override stuff, but it helps with debugging.
   */

  function HTMLScriptElementOverride() {
    var script = new HTMLScriptElement;
    onnext(function(){ handleAsync(script); });
    return script;
  }
}

/**
 * Handle errors in events.
 *
 * @see http://stackoverflow.com/questions/951791/javascript-global-error-handling/31750604#31750604
 */

function handleEvents() {
  var addEventListenerx = window.EventTarget.prototype.addEventListener;
  window.EventTarget.prototype.addEventListener = addEventListener;
  var removeEventListenerx = window.EventTarget.prototype.removeEventListener;
  window.EventTarget.prototype.removeEventListener = removeEventListener;

  function addEventListener(event, handler, bubble) {
    var handlerx = wrap(handler);
    return addEventListenerx.call(this, event, handlerx, bubble);
  }

  function removeEventListener(event, handler, bubble) {
    handler = handler._witherror || handler;
    removeEventListenerx.call(this, event, handler, bubble);
  }

  function wrap(fn) {
    fn._witherror = witherror;

    function witherror() {
      try {
        fn.apply(this, arguments);
      } catch(e) {
        window.onanyerror.apply(this, e);
        throw e;
      }
    }
    return fn;
  }
}

/**
 * Handle image/ajax request errors generically.
 */

function handleAsync(obj) {
  var onerrorx = obj.onerror;
  obj.onerror = onerror;
  var onabortx = obj.onabort;
  obj.onabort = onabort;
  var onloadx = obj.onload;
  obj.onload = onload;

  /**
   * Handle `onerror`.
   */

  function onerror(error) {
    window.onanyerror.call(this, error);
    if (onerrorx) return onerrorx.apply(this, arguments);
  };

  /**
   * Handle `onabort`.
   */

  function onabort(error) {
    window.onanyerror.call(this, error);
    if (onabortx) return onabortx.apply(this, arguments);
  };

  /**
   * Handle `onload`.
   *
   * For images, you can get a 403 response error,
   * but this isn't triggered as a global on error.
   * This sort of standardizes it.
   *
   * "there is no way to get the HTTP status from a
   * request made by an img tag in JavaScript."
   * @see http://stackoverflow.com/questions/8108636/how-to-get-http-status-code-of-img-tags/8108646#8108646
   */

  function onload(request) {
    if (request.status && request.status >= 400) {
      window.onanyerror.call(this, request);
    }
    if (onloadx) return onloadx.apply(this, arguments);
  }
}

/**
 * Generic error handler.
 *
 * This shows the basic implementation,
 * which you could override in your app.
 */

function onanyerrorx(entity) {
  var display = entity;

  // ajax request
  if (entity instanceof XMLHttpRequest) {
    // 400: http://example.com/image.png
    display = entity.status + ' ' + entity.responseURL;
  } else if (entity instanceof Event) {
    // global window events, or image events
    var target = entity.currentTarget;
    display = target;
  } else {
    // not sure if there are others
  }

  capture(entity);
  console.log('[onanyerror]', display, entity);
}

/**
 * Capture stuff for debugging purposes.
 *
 * Keep them in memory so you can reference them
 * in the chrome debugger as `onanyerror0` up to `onanyerror99`.
 */

function capture(entity) {
  captures.push(entity);
  if (captures.length > 100) captures.unshift();

  // keep the last ones around
  var i = captures.length;
  while (--i) {
    var x = captures[i];
    window['onanyerror' + i] = x;
  }
}

/**
 * Wait til next code execution cycle as fast as possible.
 */

function onnext(fn) {
  setTimeout(fn, 0);
}

})();

다음과 같이 사용할 수 있습니다.

window.onanyerror = function(entity){
  console.log('some error', entity);
};

전체 스크립트에는 기본 구현이있어 수신 가능한 엔터티 / 오류의 반 읽기 가능한 “디스플레이”버전을 인쇄하려고합니다. 앱별 오류 처리기에 영감을주기 위해 사용할 수 있습니다. 기본 구현은 또한 마지막 100 개의 오류 엔티티에 대한 참조를 유지하므로 다음과 같이 발생한 후 웹 콘솔에서 검사 할 수 있습니다.

window.onanyerror0
window.onanyerror1
...
window.onanyerror99

참고 : 여러 브라우저 / 네이티브 생성자에서 메서드를 재정의하면 작동합니다. 의도하지 않은 부작용이있을 수 있습니다. 그러나 개발 중에 사용하고, 오류가 발생하는 위치를 파악하고, 개발 중에 NewRelic 또는 Sentry와 같은 서비스에 로그를 전송하여 개발 중에 오류를 측정하고 준비 중 오류를 측정 할 수 있도록하는 것이 유용했습니다. 더 깊은 수준. 그런 다음 프로덕션에서 끌 수 있습니다.

도움이 되었기를 바랍니다.


답변

// display error messages for a page, but never more than 3 errors
window.onerror = function(msg, url, line) {
if (onerror.num++ < onerror.max) {
alert("ERROR: " + msg + "\n" + url + ":" + line);
return true;
}
}
onerror.max = 3;
onerror.num = 0;


답변

이전에 연결된 onerror 콜백도 보존해야합니다.

<script type="text/javascript">

(function() {
    var errorCallback = window.onerror;
    window.onerror = function () {
        // handle error condition
        errorCallback && errorCallback.apply(this, arguments);
    };
})();

</script>