Let's say someone wrote a method like this in a file called app.js
trying to peform an XHR request angainst a non existing url:
app.controller('MainCtrl', function($scope,$http) {
$scope.send = function() {
$http.get('http://run.plnkr.co/thisIs404');
};
});
I can see an error regarding URL http://run.plnkr.co/thisis404
in console and network panel :
To debug this I want to find quickly where this XHR call was made in sources (ie find the app.js
file) :
So I enable in chrome dev tools :
Debugger actually stops on XHR request, but the call stack only displays references to angular.js "core" files : no reference to app.js
anywhere to be found.
I tried this with chromium 36 and chrome 35. Only solution : search for the wrong URL in the whole code base (which in some case may be hard to do).
app.js
somwhere in the stack ?app.js
file easily from the console error ?With vanilla XHR requests (ie without angular), XHR debug call stack displays the XHR call in app.js
(which is easier to debug in this case) :
Full example here : http://plnkr.co/edit/lnCRpv?p=preview
[EDIT] As i've been asked : Angular.js is not minified in my tests.
You can obtain a stack trace from a thread – by calling the getStackTrace method on that Thread instance. This invocation returns an array of StackTraceElement, from which details about stack frames of the thread can be extracted.
You can view the call stack by entering one of the k (Display Stack Backtrace) commands in the Debugger Command window.
A full stack trace allows you to see the chain of files from when your custom tag reached your set breakpoint. If you click on any of the pages in the caller chain then FusionDebug will show you that page and will highlight the line at which the next page in the chain was called.
So, you see, this issue is mostly because angular's $http sucks. Sorry about that.
Let's try to use the bluebird library, because it provides long stack traces.
Promise.longStackTraces();
Promise.resolve($http.get('...'));
You get the following stack trace:
Possibly unhandled Error: [object Object]
at Promise$_rejectFromThenable (http://cdn.jsdelivr.net/bluebird/1.2.4/bluebird.js:4736:52)
at wrappedErrback (https://code.angularjs.org/1.3.0-beta.5/angular.js:11334:78)
at wrappedErrback (https://code.angularjs.org/1.3.0-beta.5/angular.js:11334:78)
at wrappedErrback (https://code.angularjs.org/1.3.0-beta.5/angular.js:11334:78)
at https://code.angularjs.org/1.3.0-beta.5/angular.js:11467:76
at Scope.$eval (https://code.angularjs.org/1.3.0-beta.5/angular.js:12418:28)
at Scope.$digest (https://code.angularjs.org/1.3.0-beta.5/angular.js:12230:31)
at Scope.$apply (https://code.angularjs.org/1.3.0-beta.5/angular.js:12522:24)
at done (https://code.angularjs.org/1.3.0-beta.5/angular.js:8207:45)
at completeRequest (https://code.angularjs.org/1.3.0-beta.5/angular.js:8412:7)
(Plunker here.)
The most important line is the first: Possibly unhandled Error: [object Object]
.
Yep. An object is thrown, not a real Error
object, with the stack
property attached to it. For the reference, here is how to throw an error and keep its stack along with it: https://github.com/Ralt/newerror/blob/master/index.js
So, how to fix this? It depends on several decisions:
If you want to add a real Promise lib, use bluebird. AFAIK, it is one of the few that provides long stack traces, and it is the fastest one out there.
For a proper xhr lib that throws real errors, I'm afraid you're out of luck there. Writing a custom one with the support for browsers you want isn't really hard though. With no IE8 support, this works (with bluebird):
function xhr(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(xhr.responseText);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
});
}
(Plunker here.)
As you can see, the stack trace is informative:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With