We need to divide the types of events. Errors of HTTP and of compilation.
They are detected/captured differently.
I will refer first to HTTP errors which I believe is the focus of the question, and then I refer to other very inspired by this response in the Soen.
HTTP
When we have an external resource that needs to be loaded, it can happen that this feature fails to load. Because it could not be downloaded, or because its content could not be interpreted/compiled, ie is not executable.
These errors are hard to detect and we don’t know much about them.
There are several ways to load external components. Via HTML with tags like script
, img
, link
, via AJAX or for example via iframe
.
Clicking on the document with script
, img
, link
When a resource does not load we can detect it globally or locally in the tag.
I’ve been comparing the events we received from window.addEventListener('error',
and <script onerror=
and it seems to me that you both have the same information.
// usei este script para percorrer os eventos e comparar
// o seu conteúdo nos dois primeiros níveis
for (var k in e) {
if (e[k] &&typeof e[k] == 'string') console.log(k, e[k])
if (typeof e[k] == 'object') {
for (var p in e[k]) {
if (e[k][p] && typeof e[k][p] == 'string') console.log(p, e[k][p])
}
}
}
Thus using:
window.addEventListener('error', function(e) {
getDetails(e, 'global');
}, true);
or using:
<div onerror="console.log(event, 'div')">
<script onerror="getDetails(event, 'script')" src="lfdghjdf.js"></script>
</div>
I get the same results. Of course <div onerror
is never called because the event error
is not propagated in the DOM.
The test I took was:
<script>
function getDetails(e, where) {
var info = {
targetInfo: {}
};
var props = ["type", "bubbles", "cancelable", "view", "detail", "message"];
props.forEach(function(prop) {
info[prop] = e[prop];
});
["tagName", "outerHTML", "src"].forEach(function(prop) {
info.targetInfo[prop] = e.target[prop];
});
info.targetInfo.srcValue = e.target.attributes.src.value;
var json = JSON.stringify(info, null, 4);
console.log(where);
console.log(json);
console.log('-----------------');
}
window.addEventListener('error', function(e) {
getDetails(e, 'global');
}, true);
</script>
<div onerror="console.log(event, 'div')">
<script onerror="getDetails(event, 'script')" src="lfdghjdf.js"></script>
</div>
And the result:
global
{
"targetInfo": {
"tagName": "SCRIPT",
"outerHTML": "<script onerror=\"getDetails(event, 'script')\" src=\"lfdghjdf.js\"></script>",
"src": "https://fiddle.jshell.net/toyubp9L/show/lfdghjdf.js",
"srcValue": "lfdghjdf.js"
},
"type": "error",
"bubbles": false,
"cancelable": false
}
-----------------
{
"targetInfo": {
"tagName": "SCRIPT",
"outerHTML": "<script onerror=\"getDetails(event, 'script')\" src=\"lfdghjdf.js\"></script>",
"src": "https://fiddle.jshell.net/toyubp9L/show/lfdghjdf.js",
"srcValue": "lfdghjdf.js"
},
"type": "error",
"bubbles": false,
"cancelable": false
}
This method detects resource access failures, to fail to compile phallus in the next section.
Loading via iframe
Here we are with our hands tied. As far as I know, no access to window
of iframe
there is no way to know that an error has occurred.
Loading via AJAX
Assuming that we load all external resources via AJAX it is possible which component had problems because we can isolate each component much better. I won’t stretch with ajax for now, but ajax has its own event error
that we can use and once we call a resource one to one we know which failure.
Compilation errors
Here we have more information about what is happening because the browser tries to compile code and when it fails to share via window.onerror
.
Note that the window.onerror
receives much more information than the elemento.onerror
, hence it is preferable to debug.
The types of error it records:
unspoken mistakes
- Throw "messages from the browser"
- variables();
- cross_origin_iframe.contentWindow.Document;, security holes like CORS
compilation errors
<script>{</script>
<script>for(;)</script>
<script>"oops</script>
setTimeout("{", 10);
, because "{" will be compiled with script
An example of code that will give build error (parse error) could be:
function foo(){
{{{...
or more natural to happen:
var hoje = new Date();
alert(hoj); // esqueci o "e"
This could be detected with
window.onerror = function(msg, url, line, col, error) {
// col & error são recentes, inseriram-se no HTML5
var extra = !col ? '' : '\ncolumn: ' + col;
extra += !error ? '' : '\nerror: ' + error;
alert("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);
return true; // para evitar alert no IE
};
An example would be:
<script>
window.onerror = function(msg, url, line, col, error) {
// col & error são recentes, inseriram-se no HTML5
var extra = !col ? '' : '\ncolumn: ' + col;
extra += !error ? '' : '\nerror: ' + error;
alert("Error: " + msg + "\nurl: " + url + "\nline: " + line + extra);
return true; // para evitar alert no IE
};
</script>
<script>!{..</script>
This method can be very useful for local scripts, and with this information send for example with AJAX error information to the server and thus detect errors in the clients.
However, if the script that has build problems is external, it will be interpreted/compiled in the global context and we can’t get anything out of it... only it happened.
Note:
The addEventListener
does not detect build errors. That is why I use this method. The onerror
is better at compiling errors because it passes more arguments.
Here’s an example I tried in Chrome: https://jsfiddle.net/bj7478g4/
References:
(In English)
@Guilhermenascimento From a look in that article, of an attention in the Capture the Stack, where the property is mentioned
stack
. Maybe it’ll help something.– stderr
@zekk seems that unfortunately the
event.error
is only available for things like "parse", for things likenew Image();
or DOM elements it always returnsundefined
– Guilherme Nascimento
Maybe - and this is just a guess - errors like these that you want to capture only exist in the capture phase, and not in the bubbling phase (so use
useCapture
false does not catch these errors). And if the error handling in the capture phase is substantially different from the bubbling phase, maybe these "error details" don’t even exist in the way you expect. It would take someone with more experience to comment, because from what I see the capture phase is rarely used (I myself cost to discover that it even existed), which makes it difficult to find details of its operation.– mgibsonbr
@mgibsonbr I think this correct, I mean, not by useCapture, but by the moment, assuming there is an Interface called Errorevent, it must be Generica, being an error in javascript it will have more properties in the object, being HTTP error it will use only the basic interface to trigger the event. For example, as zekk said, some properties were only implemented after.
– Guilherme Nascimento