Get browser to show error when javascript fails - javascript

I'm new to JavaScript development. There's one problem I find annoying in particular, and I'm hoping there's a solution to it I haven't found yet.
The problem concerns feedback/debugability when JavaScript execution fails. Whenever 'normal' languages would throw an exeption, the JavaScript execution just stops without any message.
For example, I have this code:
var Something = function() {
var self = this;
self.oneMethod = function () { /*whatever*/ };
self.otherMethod = function() { /*whatever*/ };
}
var instance = new Something();
instance.oneMethod(); // fine
instance.wrongMethodCall(); // does not exist!
I would expect that last line to give an error, somehow, somewhere. But no, my browser console remains empty. Can I change something (either in the code or in my browser, Chrome) so that this will give an error, preferably with the line it occurred on (such as a throw statement would)?

Make sure that do not have filters set for your Developer Tools

Use console.log
Apply console.log('text here') in and around new functions during development to better track the code's progression. You should do something like the following:
var Something = function() {
console.log('Constructor for "Something" successfully called.');
var self = this;
self.oneMethod = function () { /*whatever*/ };
self.otherMethod = function() { /*whatever*/ };
}
console.log('Attempting to create new object: Something . . .');
var instance = new Something();
console.log('Object created: ', instance);
console.log('Performing "oneMethod" method of object "Something" . . .');
instance.oneMethod(); // fine
console.log('Performing "wrongMethodCall" method of object "Something" . . .');
instance.wrongMethodCall(); // does not exist!
This will help you to identify where your code is breaking, why, and can also return enumerated objects to help you review the methods, properties, and prototypes of new constructs.

Related

Custom JQuery Plugin Method error

I've been working on writing a custom jquery plugin for one of my web applications but I've been running into a strange error, I think it's due to my unfamiliarity with object-oriented programming.
The bug that I've been running into comes when I try to run the $(".list-group").updateList('template', 'some template') twice, the first time it works just fine, but the second time I run the same command, I get an object is not a function error. Here's the plugin code:
(function($){
defaultOptions = {
defaultId: 'selective_update_',
listSelector: 'li'
};
function UpdateList(item, options) {
this.options = $.extend(defaultOptions, options);
this.item = $(item);
this.init();
console.log(this.options);
}
UpdateList.prototype = {
init: function() {
console.log('initiation');
},
template: function(template) {
// this line is where the errors come
this.template = template;
},
update: function(newArray) {
//update code is here
// I can run this multiple times in a row without it breaking
}
}
// jQuery plugin interface
$.fn.updateList = function(opt) {
// slice arguments to leave only arguments after function name
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function() {
var item = $(this), instance = item.data('UpdateList');
if(!instance) {
// create plugin instance and save it in data
item.data('UpdateList', new UpdateList(this, opt));
} else {
// if instance already created call method
if(typeof opt === 'string') {
instance[opt](args);
}
}
});
}
}(jQuery));
One thing I did notice when I went to access this.template - It was in an array so I had to call this.template[0] to get the string...I don't know why it's doing that, but I suspect it has to do with the error I'm getting. Maybe it can assign the string the first time, but not the next? Any help would be appreciated!
Thanks :)
this.template = template
Is in fact your problem, as you are overwriting the function that is set on the instance. You end up overwriting it to your args array as you pass that as your argument to the initial template function. It basically will do this:
this.template = ["some template"];
Thus the next time instance[opt](args) runs it will try to execute that array as if it were a function and hence get the not a function error.
JSFiddle

need help understanding closures usage in this code

Here is a simplified snippet from some code I wrote for managing tablet gestures on canvas elements
first a function that accepts an element and a dictionary of callbacks and register the events plus adding other features like 'hold' gestures:
function registerStageGestures(stage, callbacks, recieverArg) {
stage.inhold = false;
stage.timer = null;
var touchduration = 1000;
var reciever = recieverArg || window;
stage.onLongTouch = function(e) {
if (stage.timer) clearTimeout(stage.timer);
stage.inhold = true;
if (callbacks.touchholdstart) callbacks.touchholdstart.call(reciever, e);
};
stage.getContent().addEventListener('touchstart', function(e) {
e.preventDefault();
calcTouchEventData(e);
stage.timer = setTimeout(function() {
stage.onLongTouch(e);
}, touchduration);
if (callbacks.touchstart) callbacks.touchholdstart.call(reciever, e);
});
stage.getContent().addEventListener('touchmove', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdmove) callbacks.touchholdmove.call(reciever, e);
} else {
if (callbacks.touchmove) callbacks.touchmove.call(reciever, e);
}
});
stage.getContent().addEventListener('touchend', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdend) callbacks.touchholdend.call(reciever, e);
} else {
if (callbacks.touchend) callbacks.touchend.call(reciever, e);
}
stage.inhold = false;
});
}
later I call registerStageGestures on a few elements (represented by 'View' objects) in the same page. Something like:
function View() {
var self=this;
..
function InitView() {
...
registerStageGestures(kineticStage, {
touchstart: function(e) {
// do something
},
touchmove: function(e) {
// do something
},
touchendunction(e) {
// do something
},
touchholdstart: function(e) {
// do something
},
touchholdmove: function(e) {
// do something
},
touchholdend: function(e) {
// do something
},
}, self);
Everything works fine, however I'm left wondering about two things in the implementation of registerStageGestures:
First, is it necessary to make inhold, timer and onLongTouch members of the stage ? or will closures make everything works well if they are local vars in registerStageGestures ?
Second, is it necessary to call the callbacks with '.call(receiver,' syntax ? I'm doing this to make sure the callback code will run in the context of the View but I'm not sure if it's needed ?
any input is much appreciated
Thanks!
First, is it necessary to make inhold, timer and onLongTouch members
of the stage ? or will closures make everything works well if they are
local vars in registerStageGestures ?
As far as registerStageGestures() is concerned, var inhold, var timer and function onLongTouch(e) {...}. would suffice. The mechanism by which an inner function has automatic access to its outer function's members is known as "closure". You would only need to set stage.inhold, stage.timer and stage.onLongTouch if some other piece of code needs access to these settings as properties of stage.
Second, is it necessary to call the callbacks with '.call(receiver,'
syntax ? I'm doing this to make sure the callback code will run in the
context of the View but I'm not sure if it's needed ?
Possibly, depending on how those callbacks are written. .call() and .apply() are sometimes used when calling functions that use this internally. In both cases, the first parameter passed defines the object to be interpreted as this. Thus, javascript gives you the means of defining general purpose methods with no a priori assumption about the object to which those methods will apply when called. Similarly, you can call a method of an object in such a way that it acts on another object.
EDIT:
For completeness, please note that even in the absence of this in a function, .apply() can be very useful as it allows multiple parameters to be specified as elements of a single array, eg the ubiquitous jQuery.when.apply(null, arrayOfPromises)...
There are some simple answers, here.
First, closure:
Closure basically says that whatever is defined inside of a function, has access to the rest of that function's contents.
And all of those contents are guaranteed to stay alive (out of the trash), until there are no more objects left, which ere created inside.
A simple test:
var testClosure = function () {
var name = "Bob",
recallName = function () { return name; };
return { getName : recallName };
};
var test = testClosure();
console.log(test.getName()); // Bob
So anything that was created inside can be accessed by any function which was also created inside (or created inside of a function created in a function[, ...], inside).
var closure_2x = function () {
var name = "Bob",
innerScope = function () {
console.log(name);
return function () {
console.log("Still " + name);
}
};
return innerScope;
};
var inner_func = closure_2x();
var even_deeper = inner_func(); // "Bob"
even_deeper(); // "Still Bob"
This applies not only to variables/objects/functions created inside, but also to function arguments passed inside.
The arguments have no access to the inner-workings(unless passed to methods/callbacks), but the inner-workings will remember the arguments.
So as long as your functions are being created in the same scope as your values (or a child-scope), there's access.
.call is trickier.
You know what it does (replaces this inside of the function with the object you pass it)...
...but why and when, in this case are harder.
var Person = function (name, age) {
this.age = age;
this.getAge = function () {
return this.age;
};
};
var bob = new Person("Bob", 32);
This looks pretty normal.
Honestly, this could look a lot like Java or C# with a couple of tweaks.
bob.getAge(); // 32
Works like Java or C#, too.
doSomething.then(bob.getAge);
? Buh ?
We've now passed Bob's method into a function, as a function, all by itself.
var doug = { age : 28 };
doug.getAge = bob.getAge;
Now we've given doug a reference to directly use bobs methid -- not a copy, but a pointer to the actual method.
doug.getAge(); // 28
Well, that's odd.
What about what came out of passing it in as a callback?
var test = bob.getAge;
test(); // undefined
The reason for this, is, as you said, about context...
But the specific reason is because this inside of a function in JS isn't pre-compiled, or stored...
this is worked out on the fly, every time the function is called.
If you call
obj.method();
this === obj;
If you call
a.b.c.d();
this === a.b.c;
If you call
var test = bob.getAge;
test();
...?
this is equal to window.
In "strict mode" this doesn't happen (you get errors really quickly).
test.call(bob); //32
Balance restored!
Mostly...
There are still a few catches.
var outerScope = function () {
console.log(this.age);
var inner = function () {
console.log("Still " + this.age);
};
inner();
};
outerScope.call(bob);
// "32"
// "Still undefined"
This makes sense, when you think about it...
We know that if a function figures out this at the moment it's called -- scope has nothing to do with it...
...and we didn't add inner to an object...
this.inner = inner;
this.inner();
would have worked just fine (but now you just messed with an external object)...
So inner saw this as window.
The solution would either be to use .call, or .apply, or to use function-scoping and/or closure
var person = this,
inner = function () { console.log(person.age); };
The rabbit hole goes deeper, but my phone is dying...

Custom console log function, a console.log wrapper

function log( msgOrObj ){
if(dev_mode){
console.log({
'message': msgOrObj,
'caller': arguments.callee.caller.toString()
});
}
}
So, I have attempted to write a simple custom console log function (as above). However I am struggling to find which file and line the caller came from. The most I can see is the function that called it.
Has anyone done anything similar? Or is this even possible?
example used in somescript.js from line 70:
log('some very important message!')
Yes but it's very hacky and not cross browser-safe. You can use this as a starting point. It borrows from this answer.
window.trace = function stackTrace() {
var err = new Error();
return err.stack;
}
window.my_log = function (x) {
var line = trace();
var lines = line.split("\n");
console.log(x + " " + lines[2].substring(lines[2].indexOf("("), lines[2].lastIndexOf(")") + 1))
}
window.my_log("What light through yonder window breaks?")
Produces:
What light through yonder window breaks? (<anonymous>:2:42)
The only way I've seen to reliably extract this kind of info is to throw an error and then extract the caller info from the stack trace, something along the lines of:
function log( msgOrObj ){
if(dev_mode){
try {
in_val_id(); // force an error by calling an non-existent method
catch(err) {
// some regex/string manipulation here to extract function name
// line num, etc. from err.stack
var caller = ...
var lineNo = ...
}
console.log({
'message': msgOrObj,
'caller': caller,
'lineNo': lineNo
});
}
}
The stack in Chrome is in this form:
ReferenceError: in_val_id is not defined
at log (<anonymous>:4:13)
at <anonymous>:2:14
at <anonymous>:2:28
at Object.InjectedScript._evaluateOn (<anonymous>:581:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:540:52)
at Object.InjectedScript.evaluate (<anonymous>:459:21)
you can extract the function name with:
caller = err.stack.split('\n')[3].split('at ')[1].split(' (')[0];
using a regex here might be more performant. You'll probably need different approaches to extract this info with different browsers.
A word of warning though; throwing and handling errors is expensive so outputting a lot of log messages in this way is likely to impact on general performance, though this may be acceptable if it is specifically for a debug mode
So, this is what I went for in the end (where shout is a bespoke function only running in dev mode):
function log( msgOrObj ){
if(dev_mode){
if( typeof(window.console) != 'undefined' ){
try { invalidfunctionthrowanerrorplease(); }
catch(err) { var logStack = err.stack; }
var fullTrace = logStack.split('\n');
for( var i = 0 ; i < fullTrace.length ; ++i ){
fullTrace[i] = fullTrace[i].replace(/\s+/g, ' ');
}
var caller = fullTrace[1],
callerParts = caller.split('#'),
line = '';
//CHROME & SAFARI
if( callerParts.length == 1 ){
callerParts = fullTrace[2].split('('), caller = false;
//we have an object caller
if( callerParts.length > 1 ){
caller = callerParts[0].replace('at Object.','');
line = callerParts[1].split(':');
line = line[2];
}
//called from outside of an object
else {
callerParts[0] = callerParts[0].replace('at ','');
callerParts = callerParts[0].split(':');
caller = callerParts[0]+callerParts[1];
line = callerParts[2];
}
}
//FIREFOX
else {
var callerParts2 = callerParts[1].split(':');
line = callerParts2.pop();
callerParts[1] = callerParts2.join(':');
caller = (callerParts[0] == '') ? callerParts[1] : callerParts[0];
}
console.log( ' ' );
console.warn( 'Console log: '+ caller + ' ( line '+ line +' )' );
console.log( msgOrObj );
console.log({'Full trace:': fullTrace });
console.log( ' ' );
} else {
shout('This browser does not support console.log!')
}
}
}
log() when declared before the rest of the application can be called anywhere from within the app and give the developer all the information required plus will not run out of dev mode.
(http://webconfiguration.blogspot.co.uk/2013/12/javascript-console-log-wrapper-with.html)
Instead of using arguments you can do
function log( msg ) {
if (dev_mode) {
var e = new Error(msg);
console.log(e.stack);
}
}
This will show you the order in which all the functions were called (including line numbers and files). You can just ignore the first 2 lines of the stack (one will contain the error message and one will contain the log function since you are creating the error object within the function).
If you want a more robust logging - use A proper wrapper for console.log with correct line number? as #DoXicK suggested
I use this in Node and its particularly effective. Console.log is just a function it can be reassigned as well as stored for safe keeping and returned back after we are done. I've no reason to believe this would not work in a browser too.
//Store console.log function in an object so
//we can still use it.
theConsole = {};
theConsole.log = console.log;
//This function is called when console.log occurs
//arguments[0] is what would normally be printed.
console.log = function(){
theConsole.log(">" + arguments[0]);
}
//Call our console.log wrapper
console.log("Testing testing 123");
console.log("Check one two");
//Put back the way it was
console.log = theConsole.log;
console.log("Now normal");
There are a couple options to quickly go about this.
1 - Use console.error
Not very convenient, actual errors will go unnoticed and seeing a lot of red in your console output may have a negative impact on your morale. In short - don't use, unless it's for a very small script or some test
2 - Add your log method to the prototype of Object
to get the current scope/ module name/ etc. Much more flexible and elegant.
Object.prototype.log = function(message){
console.log({
'message': message,
'caller': this,
'stack':arguments.callee.caller.toString()
});
};
Use (anywhere) as:
this.log("foo");
You could add the techniques from this thread to get exact function name inside your object, as so:
var callerFunc = arguments.callee.caller.toString();
callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 9, callerFunc.indexOf("(")) || "anoynmous");
Yet make sure your scope is named... forcing you to go from this:
Module.method = function(){}
To this:
Module.method = function method(){}
As for line numbers, calling (new Error()) will give you access to the line number where it was called - and not even on all browsers.
Creating an elegant debugging function is a piece of work
As much as I hate to admit it, the other answer implying reg-exps over a try result seems to be the faster cure for your problem.
It seems you all are struggling too much. I have a simple one-line solution:-
//Just do this, that I have done below: HAVE FUN
var log=console.log;
log(`So this way is known as Aniket's way.`);
log(`Don't be too serious this is just the fun way of doing same thing`);
log(`Thank You`)
Try this
window.log = (() => {
if (dev_mode) {
return console.log;
} else return () => {};
})();

DevTools Console - Turn it off

I'm currently building a library in Javascript and really like Google's DevTools for debugging it. Unfortunately I don't want my library to log when I release.
This is how my logger is currently setup.
var debug = false;
var increaseSomething = function()
{
// Random Code...
if (debug) { console.log("Increased!"); }
}
Unfortunately this is quite annoying, I shouldn't have to check if debug is on before logging to the console every call.
I could try to encapsulate the console in my own logging object but I feel that wouldn't be such a great idea. Any thoughts?
You could do this?
if (!debug) {
console.log = function() {/* No-op */}
}
As you mentioned, you might not want to kill all logging for everyone. This is how I usually go about it. Define these in some utility file, as global functions. I usually add additional functions for LOG, WARN, ERROR and TRACE, and log these based on a verbosity level.
// Define some verbosity levels, and the current setting.
_verbosityLevels = ["TRACE", "LOG", "WARN", "ERROR"];
_verbosityCurrent = _verbosityLevels.indexOf("LOG");
// Helper function.
var checkVerbosity = function(level) {
return _verbosityLevels.indexOf(level) <= _verbosityCurrent;
}
// Internal log function.
var _log = function(msg, level) {
if(!debug && checkVerbosity(level)) console.log(msg);
}
// Default no-op logging functions.
LOG = function() {/* no-op */}
WARN = function() {/* no-op */}
// Override if console exists.
if (console && console.log) {
LOG = function(msg) {
_log(msg, "LOG");
}
WARN = function(msg) {
_log(msg, "WARN");
}
}
This also allows you to add important information to your log, such as time, and caller locations.
console.log(time + ", " + arguments.callee.caller.name + "(), " + msg);
This may output something like this:
"10:24:10.123, Foo(), An error occurred in the function Foo()"
I thought about encapsulating the console logger again and instead of coming up with an entire object to encapsulate the console I created a function that takes in a console method. Then it checks if debugging is on and calls the function.
var debug = true;
var log = function (logFunction) {
if (debug) {
logFunction.apply(console, Array.prototype.slice.call(arguments, 1));
}
};
var check = function (canvas) {
log(console.groupCollapsed, "Initializing WebGL for Canvas: %O", canvas);
log(console.log, "cool");
log(console.groupEnd);
};
check(document.getElementById('thing'));
I do like #Aesthete's ideas but I'm not yet wanting to make the encapsulated console.
Here is the jsfiddle as example: http://jsfiddle.net/WRe29/
Here I add a debugCall to the Objects prototype. Same as the log function just a different name so theirs no 'overlap' Now any object can call debugCall and check its debug flag.
Object.prototype.debugCall = function(logFunction)
{
if (this.debug) { logFunction.apply(console, Array.prototype.slice.call(arguments, 1)); }
};
var Thing = { debug : true /*, other properties*/ };
Thing.debugCall(console.log, "hello world");
EDIT:
My initial thoughts were to use an object as the 'configuration' to indicate whether the object should be logging. I've used this a while and liked the configuration concept but didn't think everyone would be so keen to use configuration objects in their code alongside a function being passed to a extended function on object. Thus I took the concept and instead looked at function decoration.
Function.prototype.if = function (exp) {
var exFn = this;
return function () {
if (exp) exFn.apply(this, arguments);
};
};
var debug = false;
console.log = console.log.if(debug);
console.group = console.group.if(debug);
// Console functions...
myFunction = myFunction.if(debug);
It's very simple almost unnecessary to even have a decoration function that checks an expression but I am not willing to put if statements everywhere in my code. Hope this helps someone out maybe even spark their interest with function decoration.
Note: This way will also kill logging for everyone unless you setup the if extension correctly ;) *cough some type of object/library configuration indicating debug
https://github.com/pimterry/loglevel
Log level Library::Try whether this suits ur need.

Referencing Other Functions from Name Spaced JavaScript

So I am trying to consolidate a bunch of code into some nice NameSpaced functions, but am having a tough time getting it to all work together. For example, I have this (edited down for clarity):
YW.FB = function() {
return {
init: function(fncSuc, fncFail) {
FB.init(APIKey, "/services/fbconnect/xd_receiver.htm");
FB.Bootstrap.requireFeatures(["Connect"]);
if(typeof fncSuc=='function') fncSuc();
},
login: function(fncSuc) {
this.FB.Connect.requireSession(function() {
if(typeof fncSuc=='function') fncSuc();
});
},
getUserInfo: function() {
var userInfo = new Object;
FB.Facebook.apiClient.users_getInfo([FB.Facebook.apiClient.get_session().uid],["name"],function(result, ex){
userInfo.name = result[0]['name'];
userInfo.uid = result[0]['uid'];
userInfo.url = FBName.replace(/\s+/g, '-');
return userInfo;
})
}
};
}();
On a normal page I can just do:
FB.init(APIKey, "/services/fbconnect/xd_receiver.htm");
FB.Bootstrap.requireFeatures(["Connect"]);
var userInfo = new Object;
FB.Facebook.apiClient.users_getInfo([FB.Facebook.apiClient.get_session().uid],["name"],function(result, ex){
userInfo.name = result[0]['name'];
userInfo.uid = result[0]['uid'];
userInfo.url = FBName.replace(/\s+/g, '-');
return userInfo;
})
And it works.
I have been trying to do:
YW.init();
YW.login();
YW.getUserInfo();
But it doesn't work. I keep getting 'FB.Facebook is undefined' from YW.getUserInfo
I could be doing this all wrong too. So the FB.init, FB.Facebook stuff is using the facebook connect libraries. Am I doing this all wrong?
If you look at the JavaScript that your browser has parsed in Firebug or a similar web debugger do you see the Facebook Connect JavaScript there? Looks like it's not in scope, and since FB is at the global level that means it's not in scope at all. Has nothing to do with namespaces. Global in JavaScript is global everywhere.

Categories

Resources