js exception position - javascript

For the JavaScript code like this:
try {
MyJob.process();
} catch(e) {
console.log("Exception occur!");
}
I run the code in Chrome or FireFox, When the exception happens, the line number of "Exception occur!" will be shown in console, but the original exception in MyJob won't be there. Is there any solution that show the original position where the exception happens and keep the try-catch that I write here?

window.onerror = function ( msg, url, num ) {
alert ( "Error: " + msg + "\nURL: " + url + "\nLine: " + num );
return true;
};
This will show most of the errors.
In the catch block add:
catch(e) {
console.log( e.name + ": " + e.message );
}
More about the error handling at JavaScriptkit
If the try/catch block is inside a function you could take advantage of the arguments.callee mdn msdn
function foo() {
try {
someFunction();
}
catch (e) {
var f = arguments.callee.toString().substr ( "function ".length);
f = f.substr(0, f.indexOf('('));
alert ( "Error type : " + e.name + "\nError : " + e.message + "\nIn function : " + f );
}
}
Result will be:
Error type : ReferenceError
Error : someFunction is not defined
In function : foo

Temporary comment out the try and catch, then step through with the Chrome (or Firefox) JavaScript debugging tools.
//try {
MyJob.process();
/*} catch(e) {
console.log("Exception occur!");
}*/
After identifying the issue, remove the comments to restore the original error handling.

Related

Retain value of variable inside try block globally [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
Though it is not possible to access a variable inside try block outside its scope, is there any other way to set it up so that it is could be accessible globally? I am using this is node.js.
var edata = 0;
if (file !== null)
try {
new ExifImage({ image: myfile }, function myexif(error, exifData) {
if (error) console.log('Error: ' + error.message);
else {
edata = exifData;
// console.log(edata); data is printed here as wanted.
}
});
} catch (error) {
console.log('Error: ' + error.message);
}
console.log(edata); //need to access data here (outside of the scope)
You have declared it properly https://jsfiddle.net/3u2gwfhz/
var edata = 0;
try {
edata = 2;
} catch (error) {
console.log('Error: ' + error.message);
}
try {
console.log(edata);
} catch (error) {
console.log('Error: ' + error.message);
}
But not sure about your code here, it doesn't look correct:
if (error) console.log('Error: ' + error.message);
else {
edata = exifData;
// console.log(edata); data is printed here as wanted.
return edata;
}

How do I get a simple stacktrace js example working?

I'm trying to get a very simple stacktrace.js example working. I'm trying to utilize the printStackTrace() method to do so.
Basically, I'm calling a buggy function that throws an error and a stack trace in the console. However, I want this error and stack trace displayed in the console stored inside a string and get that string printed instead.
For example if I run this function
function foo() {
var x = y;
}
I get an uncaught reference error y is not defined
I need this stored inside a string instead.
So far, I've tried the following
var error = null;
function foo(){
try {
var x = y;
} catch(e) {
error = printStackTrace(e);
}
}
foo();
console.log(error);
But it's printing a different stacktrace that I don't understand.
What's the correct way to use the printStackTrace method?
Try something like,
window.onerror = function(msg, file, line, col, error) {
var callback = function(stackframes) {
var stringifiedStack = stackframes.map(function(sf) {
return sf.toString();
}).join('\n');
alert('msg: ' + msg + ' line: ' + line + ' col: ' + col + ' error: ' + error + ' file:' + file);
};
StackTrace.get().then(callback)
};
Working Example:
window.onerror = function(msg, file, line, col, error) {
StackTrace.fromError(error).then(callback).catch(errback);
}
var errback = function(err) { console.log(err.message);
};
var callback = function(stackframes) {
var stringifiedStack = stackframes.map(function(sf) {
return sf.toString();
}).join('\n'); };
function fault() {
alert('Error will be invoked!')
throw "Test Error"
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stacktrace.js/2.0.0/stacktrace.js"></script>
<input id="a" type="button" value="Test Call!" onClick="fault();" />
but it seems that they have a bug.
If you're using stacktracejs 1.x and can't get it working, this is how you use it:
console.log( StackTrace.getSync() );
That's all.

How to find line where exception occursin javascript in browser

ASP.NET MVC4 shoping cart application implements error logging from client browser using
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
$.post('/Home/Error',
{
"errorMsg": errorMsg,
"url": url,
"lineNumber": lineNumber,
"column": column,
"errorobj": JSON.stringify(errorObj)
});
This logs strange errors about token o :
Error Uncaught SyntaxError: Unexpected token o
urls and column numbers vary a bit:
Line 1 Column 2
Line 1 Column 10 Object {}
Line 1 Column 10 Object {}
Line 1 Column 9 Object {}
Line 1 Column 1 Object {}
Line number is 1 always, object is empty.
There are 4 different column numbers: 1,2,9,10
How to find line in javascript which causes this exception ?
Exception occurs in client browser where there is no access. Only way is to
send information about js code line to browser.
Those pages contain few ajax calls. /Store/Browse contains ajax to add item to cart:
request = $.post('/Store/AddToCart',
serializedData, function (response) {
$("#cart-status").text(response.Total);
$inputs.prop("disabled", false);
var xx = $form[0].quantity;
$($form[0].quantity).css("background-color", "green");
showMessage(response.Message);
showFadeOutMessage(response.Message);
})
.fail(function (jqXHR, textStatus, errorThrown) {
alert('Error ' + textStatus);
})
.always(function () {
$inputs.prop("disabled", false);
});
It is possible to add lastLine assignments to code like
var lastLine;
lastLine="request = $.post('/Store/AddToCart";
request = $.post('/Store/AddToCart',
serializedData, function (response) {
lastLine='$("#cart-status").text(response.Total)';
$("#cart-status").text(response.Total);
lastLine='$inputs.prop("disabled", false)';
$inputs.prop("disabled", false);
...
and send lastLine value to server in window.onerror but this requires lot of code changes manually.
Is there a better way to find line here error occurs and maybe stack trace also ?
window.onerror is different between IE, Chrome and Firefox. Your code will work in IE. This code will work in IE and chrome.
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
$.post('/Home/Error',
{
"errorMsg": errorMsg,
"url": url,
"lineNumber": lineNumber,
"column": column,
"errorobj": errorObj ? errorObj.stack : ''
});
In Chrome errorObj contains three properties: name, stack and message- but all are getter. JSON.parse doesn't handle functions and getter is a function.
For example (Chrome only!)
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
console.log(JSON.stringify(errorObj)); // {}
console.log(errorObj.stack); //SyntaxError: Unexpected token o
// at Object.parse (native)
// at foo (http://www.example.com/index.js:8:10)
// at ...
console.log(errorObj.message); // Unexpected token o
console.log(errorObj.name); // SyntaxError
}
In IE errorObj it's simple object. But errorObj.stack is clearer.
Firefox does not send errorObj argument. You need wrap the code with try catch (or override JSON.parse and wrap the call with try catch), and send e.toString() and e.stack. For example:
var bckJSON = JSON.parse;
JSON.parse = function () {
try {
bckJSON.apply(argumetns};
} catch (e) {
// send e.toString() + '\n' + e.stack
}
}
Sorry about previous non-useful answers...
The error 'Error Uncaught SyntaxError: Unexpected token o' is occur when you invoke JSON.parse with object.
Probably this code happens -
JSON.parse({});
JQuery, in some cases, use $.parseJSON to convert ajax queries without check if the data is string. I don't know when this happens.
You can workaround in this way:
(Use $.parseJSON because it handle browser without JSON library)
JsonParseFix.js
function isString(value) {
return Object.prototype.toString.call(value) === "[object String]";
}
var bckJSONparse = $.parseJSON;
$.parseJSON = function(text, reviver) {
if (!isString(text)) {return text};
bckJSONparse.apply(arguments);
};
test.js
function test(value, message) {
try {
$.parseJSON(value);
console.log('Test succeed: ' + message);
} catch (e) {
alert('Test failed: ' + message);
}
}
test({}, 'Empty object');
test('<', 'UnSupported strings'); // Failed!
Angular solve this in a similar way (angular.fromJson documentation).
(Sorry about my english...)
Based on Elad's andwer and comments I created the following method which returns call stack in IE, Chrome and FireFox:
window.onerror = function (errorMsg, url, lineNumber, column, errorObj) {
var stack;
// Firefox does not send errorObj argument. Wrap the code with try catch
// and send e.toString() and e.stack.
try {
stack = errorObj ? errorObj.stack : '';
} catch (e) {
stack = e.toString() + " stack " + e.stack;
}
$.ajax('/api/errorlog?' + $.param({
errorMsg: errorMsg,
url: url,
lineNumber: lineNumber,
column: column
}),
{
data: JSON.stringify({ stack: stack }),
type: 'POST',
dataType: 'json',
contentType: "application/json"
});
alert(errorMsg + ' Line ' + lineNumber + ' Column ' + column + '\n\n' + stack);
};

Retrieved anchors list gets corrupted?

I am trying to analyze anchor links ( their text property ) in PhantomJS.
The retrieval happens here:
var list = page.evaluate(function() {
return document.getElementsByTagName('a');
});
this will return an object with a property length which is good (the same length I get when running document.getElementsByTagName('a'); in the console). But the vast majority of the elements in the object have the value of null which is not good.. I have no idea why this is happening.
I have been playing with converting to a real array thru slice which did no good. I have tried different sites, no difference. I have dumped the .png file to verify proper loading and the site is properly loaded.
This is obviously not the full script, but a minimal script that shows the problem on a well known public site ;)
How can I retrieve the full list of anchors from the loaded page ?
var page = require('webpage').create();
page.onError = function(msg, trace)
{ //Error handling mantra
var msgStack = ['PAGE ERROR: ' + msg];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function(t) {
msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : ''));
});
}
console.error(msgStack.join('\n'));
};
phantom.onError = function(msg, trace)
{ //Error handling mantra
var msgStack = ['PHANTOM ERROR: ' + msg];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function(t) {
msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function +')' : ''));
});
}
console.error(msgStack.join('\n'));
phantom.exit(1);
};
function start( url )
{
page.open( url , function (status)
{
console.log( 'Loaded' , url , ': ' , status );
if( status != 'success' )
phantom.exit( 0 );
page.render( 'login.png');
var list = page.evaluate(function() {
return document.getElementsByTagName('a');
});
console.log( 'List length: ' , list.length );
for( var i = 0 ; i < list.length ; i++ )
{
if( !list[i] )
{
console.log( i , typeof list[i] , list[i] === null , list[i] === undefined );
//list[i] === null -> true for the problematic anchors
continue;
}
console.log( i, list[i].innerText , ',' , list[i].text /*, JSON.stringify( list[i] ) */ );
}
//Exit with grace
phantom.exit( 0 );
});
}
start( 'http://data.stackexchange.com/' );
//start( 'http://data.stackexchange.com/account/login?returnurl=/' );
The current version of phantomjs permits only primitive types (boolean, string, number, [] and {}) to pass to and from the page context. So essentially all functions will be stripped and that is what DOM elements are. t.niese found the quote from the docs:
Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.
Closures, functions, DOM nodes, etc. will not work!
You need to do a part of the work inside of the page context. If you want the innerText property of every node, then you need to map it to a primitive type first:
var list = page.evaluate(function() {
return Array.prototype.map.call(document.getElementsByTagName('a'), function(a){
return a.innerText;
});
});
console.log(list[0]); // innerText
You can of course map multiple properties at the same time:
return Array.prototype.map.call(document.getElementsByTagName('a'), function(a){
return { text: a.innerText, href: a.href };
});

Finding meta “description” using Javascript

I was trying to pass a tab object tabout in order to find the description and title of the webpage.
When I was debugging the code with some breakpoints, it was returning value, but when I am running it, it's not returning the description.
Is there any problem with the code?
function computeDescription(tabout)
{
var code = 'var meta = document.querySelector("meta[name=\'description\']");' +
'if (meta) meta = meta.getAttribute("content");' +
'({' +
' title: document.title,' +
' description: meta || ""' +
'});';
var desc;
var message = document.querySelector('#message');
chrome.tabs.executeScript(tabout.id,{code: code}, function(results) {
if (chrome.extension.lastError) {
message.innerText = 'There was an error injecting script :\n'+chrome.extension.lastError.message;
}
if (!results) {
return;
}
var result = results[0];
// Now, do something with result.title and result.description
console.log(result.title);
console.log(result.description);
desc=result.description;
});
return desc;
}
It looks like you're assuming that the callback you give to executeScript will execute before computeDescription returns. This is not true; executeScript executes asynchronously and your callback will never run before computeDescription returns.
In order to handle this, you need to to adopt the asynchronous model for your definition of computeDescription. Rather than returning a value, take a callback argument and call it when data is ready.
function computeDescription(tabout, callback) {
var code = 'var meta = document.querySelector("meta[name=\'description\']");' +
'if (meta) meta = meta.getAttribute("content");' +
'({' +
' title: document.title,' +
' description: meta || ""' +
'});';
var message = document.querySelector('#message');
chrome.tabs.executeScript(tabout.id, {code: code}, function(results) {
if (chrome.extension.lastError) {
message.innerText = 'There was an error injecting script :\n'+chrome.extension.lastError.message;
}
if (!results) {
callback();
}
callback(results[0].description);
});
}
Then your usage similarly transforms from
console.log('Le description is: ' + computeDescription(tab));
to
computeDescription(tab, function(description) {
console.log('Le description is: ' + description);
});

Categories