I have a page which includes a js-file. It's a jquery Plugin, but I think thats not important. The plugin break with a manually thrown error at one point.
(function($) {
$.pkp.classes.Handler = function($element, options) {
/* ... */
if (this.data('handler') !== undefined) {
throw new Error('blub');
}
If I remove the line it works perfektly, so I think the check is not necessary. Unfortunatley I can not change the js-file (it would get overwritten every update), but I could savely include another one.
I tried to catch the error and let the script continue untouched as if the error throwing line where deleted.
$(window).error(function(e){
var t = 'Handler.js';
var l = t.length;
var file = e.originalEvent.filename.substr(e.originalEvent.filename.length - l, l);
if ((e.originalEvent.lineno == 38) && (file == t)) {
e.preventDefault();
return true;
}
})
I tried something similar with window.onerror. The result is, that in both cases the error doesn't appear, but the script does not continue as it would, if the line was deleted.
I know it would be better to find the source of the misbehaviour but its a very complicates bunch of scripts, and everything works still perfectly after I put a newer jQuery and a migration script there - only this single line makes problems, so I thought maybe it's more efficient just to eliminate the error without understanding it completely...
Any suggestions?
Related
I keep getting an error with roughly the following code.
38. var element_to_precede = document.getElementById("element");
39. var parent_element = element_to_precede.parentNode;
It equates roughly to
line 39: TypeError: element_to_precede is null"
I have been reading around but what I have tried just doesn't work. I have in my main.js,
'contentScriptWhen: "ready"'
in theory this is supposed to load the script only when everything else has finished loading. The only logical explanation is that this is failing somehow.
I have tried wrapping the code with
window.onload = function() {
//Summon function that calls for element_to_precede here
}
Where I ask it to load the elements. Unfortunately it doesn't seem to change anything.
I'm primarily messing with trying to create an extension so I'm using mozilla's tutorials.
Please don't suggest jQuery I'm sure there's a solution in standard JavaScript that I'm missing or not implementing correctly. I'm likely missing something fundamental but for the life of me can't figure out what it is.
Edit.
For example, the code I've tried.
window.onload=function(){
var container = document.createElement("div");
var element_to_precede = document.getElementById("element")
var parent_element = element_to_precede.parentNode;
parent_element.insertBefore(container, element_to_precede);
}
Returns
JavaScript error: line 39: TypeError: element_to_precede is null
Edit
After going through the code again I have found that contrary to what I'm being told the system does...something isn't happening
After asking it the following commands
if(document.readyState === "complete") {
console.log("In theory everything is already loaded");
console.log("Detected: " + document.getElementById("element") + " element");
}
I discovered that it would cycle round four times. Each time it would tell me that everything has already been loaded but that null element was detected. Implying that in fact the page is not "complete".
I'm tempted to just put in a wait order for 200 milliseconds or so every time it finds out that it wasn't detected.
So back to the original question. How the heck do I stop this?
I am getting a totally bizarre issue in Chrome v. 33 that looks as if the string comparison operator is broken. It only occurs with the developer tools closed. I have the following function:
function TabSelected(data) {
var tab, was_design;
this.data = data;
tab = this.data.tab;
was_design = tab === 'design';
if (this.data.tab === 'design') {
this.tab = 1;
} else {
this.tab = 2;
console.log('was_design');
console.log(was_design);
console.log('is_design');
console.log(tab === 'design');
}
}
Which I call like so:
new TabSelected({
tab: 'design'
});
I have a setInterval running that runs this code every 50 ms. Most of the time, the if statement picks the first code path, so nothing gets logged to the console. However, after about ~8 seconds, it goes down the else code path. When I open the developer tools afterwards (since the bug doesn't happen when they're closed), I see the following log output:
was_design (index):96624
false (index):96625
is_design (index):96626
true (index):96627
I am... confused by this. I've also tried logging the contents of tab, which is in fact 'design', and logging this, which is a new TabSelected instance.
Am I losing my mind? Is Chrome losing it's mind?
UPDATE: I was able to reproduce it in a simplified setting: http://jsfiddle.net/WBpLG/24/. I'm pretty sure this is a bug with Chrome and I've filed an issue, see answer below.
Make this change and the problem should go away:
if (this.data.tab === 'design') {
to
if (String(this.data.tab) === 'design') {
However, I can confirm that typeof this.data.tab === 'string' both before the if clause and during the else, so I think this is only a partial answer at best.
Alternatively, I can also clear the problem by adjusting NewElementButtonSectionOpened.prototype.previous_requirement on line 59440:
// Create a single instance of the requirement and store it in the closure.
var cachedReq = new TabSelected({ tab: 'design' });
// Now just return that one instance over and over again.
NewElementButtonSectionOpened.prototype.previous_requirement = function() {
// deleted line: return new TabSelected({ tab: 'design' });
return cachedReq;
};
While both of these solutions fix the problem on my machine, it is not clear to me why this works.
I am afraid to mention it, but at one point, I was also able to prevent the error from happening by adding a throw new Error("..."); line in your else block. In other words, changing something in the else block altered the behavior of the if check. My only clue here is that the length of the error message mattered. For a while there, I could clear the error or cause the error consistently by altering the length of an error message that would never be thrown. This is so bizarre that I must surely have been mistaken, and indeed, I can no longer replicate it.
However, this is an extremely large JavaScript file. Maybe there is something to that. Maybe it is just a ghost story. This problem is certainly quite creepy enough without it, but just in case somebody else sees something similar... You aren't alone.
I was able to create a simple reproduction case, so I've filed a bug with Chromium.
The necessary conditions seem to be: a setInterval or repeating setTimeout, an expensive computation in the body of the interval, a call to a new Object passing data that contains a string, and a string comparison.
I would like to pass errors to an alert to warn the user they made mistake in their code even if they don't have console open.
var doc=(frame.contentWindow.document || obj.contentDocument|| obj.contentWindow);
var head = doc.getElementsByTagName('head')[0];
var scriptElement = doc.createElement('script');
scriptElement.setAttribute('type', 'text/javascript');
scriptElement.text = scripts;
try{
head.appendChild(scriptElement);
}
catch(e){ alert("error:"+e.message +" linenumber:"+e.lineNumber);}
The appendChild throws an error when the scripts contain an error. It goes straight to the console though, and I want it to display in an alert, because it is for kids and they might not check the console. The try catch block does not catch the error.
I tried it with eval(scripts).
try{
eval(scripts);} catch(e){ alert("error:"+e.message +" linenumber:"+e.lineNumber);}
this does work but it means that the code is executed twice, and that is very inconvenient in some cases.
I tried monkey patching the console.error:
console.log=function(){alert("taking over the log");}
console.error=function(){alert("taking over the log");}
but that only works when I literally use console.error. Not when an actual error is thrown.
What function sends the error to the console in the case of a real error,if it isn't console.error? and can I access it and change it?
Any ideas? Help would be really appreciated.
Thanks Jenita
Whilst try ... catch will work on the code that the script runs initially, as Jenita says it won't catch Syntax Errors, and also it won't catch errors thrown by callback functions which execute later (long after the try-catch has finished). That means no errors from any functions passed to setTimeout or addEventListener.
However, you can try a different approach. Register an error listener on the window.
window.addEventListener("error", handleError, true);
function handleError(evt) {
if (evt.message) { // Chrome sometimes provides this
alert("error: "+evt.message +" at linenumber: "+evt.lineno+" of file: "+evt.filename);
} else {
alert("error: "+evt.type+" from element: "+(evt.srcElement || evt.target));
}
}
This will be called when an exception is thrown from a callback function. But it will also trigger on general DOM errors such as images failing to load, which you may not be interested in.
It should also fire on Syntax Errors but only if it was able to run first so you should put it in a separate script from the one that may contain typos! (A Syntax Error later in a script will prevent valid lines at the top of the same script from running.)
Unfortunately, I never found a way to get a line number from the evt in Firefox. (Edit: Poke around, I think it might be there now.)
I discovered this when trying to write FastJSLogger, an in-page logger I used back when the browser devtools were somewhat slow.
Desperate to catch line numbers, I started to experiment with wrappers for setTimeout and addEventListener that would re-introduce try-catch around those calls. For example:
var realAddEventListener = HTMLElement.prototype.addEventListener;
HTMLElement.prototype.addEventListener = function(type,handler,capture,other){
var newHandler = function(evt) {
try {
return handler.apply(this,arguments);
} catch (e) {
alert("error handling "+type+" event:"+e.message +" linenumber:"+e.lineNumber);
}
};
realAddEventListener.call(this,type,newHandler,capture,other);
};
Obviously this should be done before any event listeners are registered, and possibly even before libraries like jQuery are loaded, to prevent them from grabbing a reference to the real addEventListener before we have been able to replace it.
Ok so the less elegant but highly efficient way of doing this is 'refactoring' your innate console functions. Basically any error or warnings you get are being outputted there by a javascript function that is pretty similar to the familiar console.log() function. The functions that I am talking about are console.warn(), console.info() and console.error(). now let's 're-map' what each of those do:
//remap console to some other output
var console = (function(oldCons){
return {
log: function(text){
oldCons.log(text);
//custom code here to be using the 'text' variable
//for example: var content = text;
//document.getElementById(id).innerHTML = content
},
info: function (text) {
oldCons.info(text);
//custom code here to be using the 'text' variable
},
warn: function (text) {
oldCons.warn(text);
//custom code here to be using the 'text' variable
},
error: function (text) {
oldCons.error(text);
//custom code here to be using the 'text' variable
}
};
}(window.console));
//Then redefine the old console
window.console = console;
Now, generally I would highly advise against using something like this into production and limit it to debugging purposes, but since you are trying to develop a functionality that shows the output of the console, the lines are blurry there, so I'll leave it up to you.
You could wrap the script in its own try/catch, something like:
var doc=(frame.contentWindow.document || obj.contentDocument|| obj.contentWindow);
var head = doc.getElementsByTagName('head')[0];
var scriptElement = doc.createElement('script');
scriptElement.setAttribute('type', 'text/javascript');
scriptElement.text = "try{"+scripts+"}catch(e){console.error(e);alert('Found this error: ' + e +'. Check the console.')}"
head.appendChild(scriptElement);
To shortcut a long comment section on "don't use new Function" and/or "eval is evil", this question is about how to access, if possible, error information that is related to a new Function() constructor failing. It's mostly a question to discover a limit in what the browser will let me do when trying to exploit JavaScript to the extent that the spec and standard browser implementations allow. So with that disclaimer in place:
When evaluating code through a new Function() call, is there a way to find out where in the function's content a syntax error occurs, if illegal-syntax code is being evaluated? i.e.:
try {
var generator = new Function(input);
try {
generator();
}
catch (runtimeError) {
console.error("legal code; unforeseen result: ", runtimeError);
}
}
catch (syntaxError) {
console.error("illegal code; syntax errors: ", syntaxError);
}
When the building of the generator fails, is there a way to find out (from the browser, not using jslint or another external library) what the error was or where it occurred?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError/prototype mentions that a SyntaxError has a filename and linenumber property, but these are undefined for dynamic code evaluated through a new Function() constructor from what I can tell, so relying on the error object itself seems not to be an option. Are there alternative ways to introduce the code to the browser so that the code, once we know it has syntax errors from a failing new Function call, can be used to find out where the problem is according to the JS engine used?
(Of course, if the goal was to simply find syntax errors, jslint as a preprocess step would be the go-to solution, but I'm more interested in whether or not browsers can in some way be made to report this information, even if in limited form like "there is SOME error on line/char ...")
afaik impossible to find out where it occured. but you may want to see Exception.message to fetch information what the error was.
example: http://jsbin.com/IRoDiJIV/1/watch?js
Found a solution myself using a simiar method to setting breakpoints in evaled code
In chrome dev tools's sources panel, I put the following in a conditional breakpoint on the new Function line (since it's library code and I can't change it.)
(function(eval_js, load_js) {
try {
eval(eval_js);
} catch (e) {
(function addCode(js) {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = 'data:text/javascript;charset=utf-8,' + escape(js);
document.body.appendChild(e);
console.warn("Inserted Script for ", js);
})(load_js.replace(/;/g,";\n"));
handlerCode = "";
return false;
}
return false;
})("new Function('event', handlerCode)", handlerCode)
I am using a javascript called 'Facelift 1.2' in one of my websites and while the script works in Safari 3, 4b and Opera, OmniWeb and Firefox it does not in any IE version.
But even in the working browser i get the following error I cannot decipher.
Maybe in due time—with more experience in things Javascript—I will be able to but for now I thought I would ask some of you, here at SO.
The following is the error popup i get in IETester testing the page for Interet Explorer 6,7 and 8:
The following is from the Firebug console in Firefox 3.0.6:
The website is: http://www.457cc.co.nz/index.php In case it helps you see the problem mentioned in action.
I have also looked up what line 620 corresponds to which is:
"line 76" is:
this.isCraptastic = (typeof document.body.style.maxHeight=='undefined');
which is part of this block of code (taken from the flir.js):
// either (options Object, fstyle FLIRStyle Object) or (fstyle FLIRStyle Object)
,init: function(options, fstyle) { // or options for flir style
if(this.isFStyle(options)) { // (fstyle FLIRStyle Object)
this.defaultStyle = options;
}else { // [options Object, fstyle FLIRStyle Object]
if(typeof options != 'undefined')
this.loadOptions(options);
if(typeof fstyle == 'undefined') {
this.defaultStyle = new FLIRStyle();
}else {
if(this.isFStyle(fstyle))
this.defaultStyle = fstyle;
else
this.defaultStyle = new FLIRStyle(fstyle);
}
}
this.calcDPI();
if(this.options.findEmbededFonts)
this.discoverEmbededFonts();
this.isIE = (navigator.userAgent.toLowerCase().indexOf('msie')>-1 && navigator.userAgent.toLowerCase().indexOf('opera')<0);
this.isCraptastic = (typeof document.body.style.maxHeight=='undefined');
if(this.isIE) {
this.flirIERepObj = [];
this.flirIEHovEls = [];
this.flirIEHovStyles = [];
}
}
The whole script is also available on my server: http://www.457cc.co.nz/facelift-1.2/flir.js
I just don't know where to start looking for the error, especially since it only affects IE but works in the rest. Maybe you guys have an idea. I would love to hear them.
Thanks for reading.
Jannis
PS: This is what Opera's error console reports:
JavaScript - http://www.457cc.co.nz/index.php
Inline script thread
Error:
name: TypeError
message: Statement on line 620: Cannot convert undefined or null to Object
Backtrace:
Line 620 of linked script http://www.457cc.co.nz/facelift-1.2/flir.js
document.body.appendChild(test);
Line 70 of linked script http://www.457cc.co.nz/facelift-1.2/flir.js
this.calcDPI();
Line 2 of inline#1 script in http://www.457cc.co.nz/index.php
FLIR.init();
stacktrace: n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'
I agree with tvanfosson - the reason you're getting that error is quite likely because you're calling init() before the page is done loading, so document.body is not yet defined.
In the page you linked, you should move the following code to the bottom of the page (just before the closing html tag:
<script type="text/javascript">
FLIR.init({ path: 'http://www.457cc.co.nz/facelift-1.2/' });
FLIR.auto();
</script>
Even better, you should attach the initialization to the document's ready event. If you do it this way, there is no need to even move your javascript to the bottom of the file. Using jquery:
$(document).ready( function(){
FLIR.init({ path: 'http://www.457cc.co.nz/facelift-1.2/' });
FLIR.auto();
});
More on jquery's document.ready event »
Edit Answer left for context. See #Triptych's (accepted) answer for the correct resolution.
My suggestion is to move the inclusion of the javascript to the end of your mark up. I think what is happening is that the code is executing before the DOM is completely loaded and thus the document.body is null when you try to reference it in determining the maxHeight style property. Moving the inclusion of the javascript to the end of your markup should be enough to guarantee that the body of the document is loaded at least and avoid this particular error.
... rest of html....
<script type='text/javascript'
src='http://www.457cc.co.nz/facelift/flir.js'>
</script>
</body>
</html>
Install .net Framework v2 and solve the problem.