Proper way for debug symbols in javascript - javascript

When i write javascript code , i usually insert a debug symbols to help me out .
Let me illustrate what i mean by example :
var debug = true;
/* Some event handler */
onValueChange = function(e, ui){
var new_value = dom.volume.slider("value");
conf.value = new_value;
if (debug) {
console.log("Value changed to : " + new_value);
}
}
when i finish, i don't want all this debug related code to be part of my release/minified codebase .
what is the convention for this sort of thing ? are there any (non IDE based) tools available ?
I am looking for solutions working with exiting codebase and for starting a new project in the future .
Or what other debugging strategies exist in javascript world ?

To get rid of this logging code you will need to write a parser! I suggest that you go with a different debugging strategy. console.log is no doubt useful but a full fledged debugger like: the one provided by Chrome DevTools, is strongly advised.
You can inject break points at any position in your code with debugger;. Going with a real debugger will make your life as a developer much more easier.

Use FireBug in Fire Fox . it will help you a lot to debug java script code.

Related

How can I print functions in Node.js the same way Firefox prints functions (namely giving a name)?

var fun1=function(){console.log('hello');}
var fun2=fun1
console.log(fun2);
The above code run in Firefox prints fun2. In Chrome it prints the function body, in Node.js it prints Function.
Why is this difference?
How can I get Firefox's behaviour in Node.js ?
Why I am asking this ?
I am asking this because I would like to debug JS code generated from Idris where the JS runtime uses explicit call stack, and I would like to print the callstack content in a meaningful way and Firefox does that the best but I want to debug code on Node.js hence I would like to get Node.js to print functions as Firefox, how can I do that ?
EDIT:
A typical compiled function looks like this:
var _idris__123_io_95_bind2_125_ = function(oldbase){
var myoldbase = new i$POINTER();
i$valstack_top += 1;
i$ret = new i$CON(65646,[i$valstack[i$valstack_base],i$valstack[i$valstack_base + 1],i$valstack[i$valstack_base + 2],i$valstack[i$valstack_base + 3],i$valstack[i$valstack_base + 4],i$valstack[i$valstack_base + 5]],_idris__123_APPLY0_125_$65646,null);
i$valstack_top = i$valstack_base;
i$valstack_base = oldbase.addr;
}
So here the useful information is the variable name _idris__123_io_95_bind2_125_ itself, and that is what is printed by Firefox, but not by node.js, and that is the problem, Firfox prints useful information, node.js does not.
So the question is, how can I make node.js to print _idris__123_io_95_bind2_125_ for the above function ?
EDIT 2:
Trying some of the suggestions don't work unfortunately :
>cat deb.js
var fun1=function(){console.log('hello');}
var fun2=fun1
console.log(fun2);
console.log(fun2.name);
console.log(fun2.toString());
console.log(fun2+'');
>node deb.js
[Function]
function (){console.log('hello');}
function (){console.log('hello');}
>
you need to convert it to string try this :
console.log(fun2.toString());
UPDATE: Works with v0.12.7 as well. So I guess it would work with all node versions.
In node Following works
function someCoolFuntion (){
/* Some code */
}
var fun1 = someCoolFuntion;
//Show name; Similar to Firefox's behaviour!
console.log(fun1.name)
//Show fullbody; Chrome's behaviour (as shaouari suggested)
console.log(fun1.toString());
Output
Hope this helps!

Google Scripts/Basic JavaScript - Issue fixed by debugger

I'm working on a Google Scripts add on for Google Sheets, but I'm trying to get the script working before I actually set it up on the sheet. The code below works fine if I set a breakpoint somewhere in the extractNumbers function. If I just execute the code without breakpoints, I get an error:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
Here's the code:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
function phoneCheck(newCell,newHome,oldCell,oldHome) {
Logger.clear();
var newCell = extractNumbers(newCell);
var oldCell = extractNumbers(oldCell);
var newHome = extractNumbers(newHome);
var oldHome = extractNumbers(oldHome);
if (newCell === oldCell) {
return newCell;
exit;
} else if (newCell === oldHome && newHome === oldCell) {
return oldCell;
exit;
}
if (newCell === '' && oldCell !== '' ) {
return oldCell;
exit;
}
if (newCell !== oldCell && newCell !== oldHome) {
return newCell;
exit;
}
return "No value found";
exit;
}
function extractNumbers(input) {
Logger.log(input);
var str = input;
return str.replace( /\D+/g, '');
}
Now I realize my if/then logic is more than a bit inelegant, but for my purposes, quick and dirty is fine. I just need it to run.
ALSO, I have read of other novice JavaScript programmers having similar issues related to the sequence of code execution. If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too. Thanks!
EDIT: I put my code into a new fiddle and it works fine, but it continues to fail in Google Scripts editor unless running in debug mode with a breakpoint. The problem seems to be that the function parameters aren't available to the function unless there is a breakpoint. Anyone have access to Google Scripts that can try my updated code from https://jsfiddle.net/hrzqg64L/ ?
None of the suggestions got to the root of your problem - and neither did your answer, although you've avoided the problem by putting an enclosure around everything.
There's no AJAX, no asynchronous behavior - it's simpler than that. "Shadowing of parameters" is likewise a red herring. Bad coding practice, yes - but not a factor here.
If someone would like to link to a concise source aimed at a non-advanced audience, that would be great too.
Sorry - no such thing. I can explain what's going on, but can't guarantee it will be accessible to novices.
The exception
Let's just clarify what causes the exception, or thrown error, that you've observed.
As written, extractNumbers() will throw an exception if it has a null parameter (or any non-string parameter) passed to it. If you choose to extractNumbers() then hit "run", you'll get:
TypeError: Cannot call method "replace" of undefined. (line 36, file "")
That is telling you that on line 36, which is return str.replace( /\D+/g, '');, the variable str contains an object that is undefined (...and has no replace() method).
For bullet-proof code, you would check your parameter(s) to ensure they are valid, and handle them appropriately. Sometimes that would be with a valid default, and other times you might return an error or throw an exception that is more explicit about the parameter problems.
Running code in Google's debugger
The only way to run code in Google's Debugger is to select a function, then choose "run" or "debug". Assuming you posted all your code, you had just two functions to choose from:
phoneCheck()
extractNumbers()
Whenever Google Apps Script runs any part of a script, the entire script is loaded and scanned to find all symbols & check syntax. The scope of all symbols is noted as well, and so are any dependencies between functions and global symbols (symbols outside of any closure, or block of code).
That takes some time. To speed things up when asked to execute a specific function, the global symbols are only evaluated if they are a dependency for the requested function or the functions it may call. There is another condition that will trigger evaluation of global symbols, and that is if there is a possibility that the debugger may need to stop and display values.
When this happens, any code that is outside a closure (outside a function, for example) will be executed. This is what you observed when you set breakpoints.
Why did it work when breakpoints were set?
As explained, just having a breakpoint set triggers evaluation of global symbols.
You start this script with a few lines of code that are not in any closure:
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
It is that code which makes the only proper invocation of phoneCheck() with parameters. Because myVar is evaluated, phoneCheck() gets called with parameters, and in turn calls extractNumbers() with a defined parameter.
Unfortunately, because of the way the debugger works, you cannot choose to run that code yourself. You need to rely on these side-effect behaviors.
How to fix this?
Simple. Don't rely on global code to invoke functions under test. Instead, write an explicit test function, and call that.
function test_phoneCheck() {
var myVar = phoneCheck("a1","a2","o1","o2");
Logger.log(myVar);
}
Finally found the issue, but I don't fully understand it.
This question got me thinking about scope and how it might be different in the Google Script environment. I figured a simple workaround would be to enclose the entire script in its own void function, and it worked! Also, I simplified the script quite a bit with an array:
function init () {
var numberArray = ["a3", "a2", "o3", "o10"];
var myVar = phoneCheck(numberArray);
Logger.log(myVar);
function phoneCheck(myArray) {
var phoneString = '';
Logger.clear();
var arrayLength = myArray.length;
for (i = 0; i < arrayLength; i++) {
phoneString += myArray[i].replace(/\D+/g, '');
}
return phoneString;
}
}
Also, I realize the functionality of this script is different than the original, but I was really just trying to solve this problem. Now that I have, I can finish the script properly.
Thanks for all the suggestions, everyone! I learned a lot of good things, even though they turned out not to be the answer.

Should I keep console statements in JavaScript application?

I am using console.log() and console.dir() statements in 3 places in my 780 lines of code JS script. But all of them are useful for debugging and discovering problems that might appear when using the application.
I have a function that prints internal application's state i.e current value of variables:
printData: function () {
var props = {
operation: this.operation,
operand: this.operand,
operandStr: this.operandStr,
memory: this.memory,
result: this.result,
digitsField: this.digitsField,
dgField: this.dgField,
operationField: this.operationField,
opField: this.opField
};
console.dir(props);
}
I also have a list of immutable "contants" which are hidden with closure but I can print them with accessor method called list(); in console.
Something like this:
list: function () {
var index = 0,
newStr = "",
constant = '';
for (constant in constants) {
if (constants.hasOwnProperty(constant)) {
index = constant.indexOf('_');
newStr = constant.substr(index + 1);
console.log(newStr + ": " + constants[constant]);
}
}
}
The third place where I use console in debugging purposes is in my init(); function, where I print exception error if it happens.
init: function (config) {
try {
this.memoryLabelField = global.getElementById(MEMORY_LABEL);
this.digitsField = global.getElementById(DIGITS_FIELD);
this.digitsField.value = '0';
this.operationField = global.getElementById(OPERATION_FIELD);
this.operationField.value = '';
return this;
} catch (error) {
console.log(error.message);
return error.message;
}
}
As my question states, should I keep these console statements in production code?
But they come very useful for later maintenance of the code.
Let me know your thoughts.
Since these are not persistent logs you won't get much benefit out of them. Also it runs on every individuals machine since everyone has their own copy of the program. If you really need it, it would be better to have a variable that can toggle this feature. Espcially if you are targetting to debug a whole lot of pre-determined stuffs.
Client Side issues needs to be debugged slightly different from Server Side. Everyone has their own copy of the program. Browser-JS is run on client side you open the browser and all code that you wrote is with you in a full blown repl and debugging is easy compared to Server side where most likely you wouldn't have access to that system. It is so flexible that you could just override it when you are checking something in production right from your own browser without affecting anyone. Just override it with those console statements and debug the issue.
Its a good idea to have logs in Server side programming. It gives a lot of useful information and is persistent.
As said above, debugging code should not be present on a production environment.
However, if you plan to keep it anyway, keep in mind that all browsers do not support it.
So you may check its availability and provide a fallback:
if (typeof window.console === 'undefined')
{
window.console = {};
}
if (typeof window.console.log === 'undefined')
{
window.console.log = function() { };
}
According to mozilla developer network
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
Leaving console.log() on production sites can cause issues since it is not supported by older browsers. It is most likely to throw exceptions in that case.
It's historically considered a bad-practice by Javascript programmers. At the start of the eons, some browsers didn't have support for it (IE8 or less for example). Other thing to take in mind is that you are making your code larger to download.

In Appcelerator Titanium How can I disable javascript code optimization to make debugging easier?

I'm working with an iOS targeted app built using Titanium (with Alloy); I want to be able to turn off the Javascript code optimization within Titanium Studio, but cannot locate anything by Googling, nor searching SO. When Titanium compiles it produces optimized javascript files...which makes interactive debugging difficult because in many cases it combines several lines of clean, readable code into a single line... which makes stepping into the code with the debugger difficult.
For example:
this...
if(Array.isArray(detailItemArray)){
//term-item.detail-items
for(var z=0;z<detailItemArray.length;z++){
if(z===0){
//first item in detail-item array gets a title pre-pended to it
// title is optional
if(_.isString(termItemArray[y].title)){
htmlArray.push(html.termItem(termItemArray[y].title,html.processStyle(detailItemArray[z]['style'],detailItemArray[z]['detail'])));
} else{
htmlArray.push(html.processStyle(detailItemArray[z]['style'],detailItemArray[z]['detail']));
}
} else {
//process style if available, then add to the array buffer
htmlArray.push(html.processStyle(detailItemArray[z]['style'],detailItemArray[z]['detail']));
}
}
} else {
//when detailArray is not an array (sometimes it is -- see if statement above)
//the title is optional
if(_.isString(termItemArray[y].title)){
htmlArray.push(html.termItem(termItemArray[y].title,detailItemArray['detail']));
} else {
htmlArray.push(html.termItemNoTitle(html.processStyle(detailItemArray['style'],detailItemArray['detail'])));
}
}
turns into this...a single line...
if (Array.isArray(detailItemArray)) for (var z = 0; detailItemArray.length > z; z++) 0 === z ? _.isString(termItemArray[y].title) ? htmlArray.push(html.termItem(termItemArray[y].title, html.processStyle(detailItemArray[z]["style"], detailItemArray[z]["detail"]))) : htmlArray.push(html.processStyle(detailItemArray[z]["style"], detailItemArray[z]["detail"])) : htmlArray.push(html.processStyle(detailItemArray[z]["style"], detailItemArray[z]["detail"])); else _.isString(termItemArray[y].title) ? htmlArray.push(html.termItem(termItemArray[y].title, detailItemArray["detail"])) : htmlArray.push(html.termItemNoTitle(html.processStyle(detailItemArray["style"], detailItemArray["detail"])));
using Titanium Studio v3.2.3.201404181442
Any ideas if there is a setting that can temporarily disable this behavior so interactive debugging is easier?
Thanks in advance.
--Scott
EDIT: A suggestion from a co-worker was to sprinkle some log statements in the code (like right after the "for" statements; and sure enough this prevented the optimizer from in-lining the code. Not exactly how I wanted to go about it, but, at least got me moving forward. Would still like to find a way to turn down the JS optimizer level or off.
Try titanium build -p ios --skip-js-minify.
From titanium build --help:
Build Flags:
--legacy build using the old Python-based builder.py; deprecated
--skip-js-minify bypasses JavaScript minification; simulator builds are never minified; only
supported for Android and iOS [default: false]
-b, --build-only only perform the build; if true, does not install or run the app
-f, --force force a full rebuild

Enable/Disable debug code dynamically

I'm writing a decent sized JavaScript animation library, that I would like to include debugging code in. I could easily do a check :
if(myLib.debugger){
console.warn('warning message');
}
However if this runs a couple thousand times a second, it would eventually cause performance issues. Add in a few more checks throughout the code and the effect will be even more noticeable.
What I'm wondering is if it would be possible to check onload if the debugger should be enabled, and if so... turn something like this:
//debugger if(!this.name) console.warn('No name provided');
into:
if(!this.name) console.warn('No name provided');
Leaving the code commented if its not enabled, and uncommenting it if it is, thus removing any possible performance issues. Could this be done somehow with a regular expression on the entire script if loaded in through ajax? I'm trying to avoid the need for 2 versions of the same code, lib.dbug.js and a lib.js.
Cross browser compatibility is not of great importance for this (I'm really only worried about new browsers), I see it as nice to have item. If its possible however, it would be a great thing to have.
Any insight would be greatly appreciated.
The simplest way to do this would be to check if the debugger should be disabled and if so, replace it with a mock object that does nothing at the very start of your script:
if (!myLib.debugger) {
window.console = (function () {
var newConsole = {};
var key;
for (key in window.console) {
if (typeof window.console[key] === 'function') {
newConsole[key] = function () {};
}
}
return newConsole;
}());
}
The overhead of this approach should be negligible.
If this is a JavaScript library... then I'd expect as a 3rd party developer that I could download/use 2 versions. The production version (no debug, AND minimized). If I wanted to debug, I would point to the debug version of the library instead.
e.g.
<script src="foo-lib-min.js"></script>
<!-- swap to this for debugging <script src="foo-lib-full.js"></script>-->

Categories

Resources