获取$ http调用的完整调用堆栈跟踪

时间:2014-06-23 11:25:30

标签: javascript ajax angularjs asynchronous google-chrome-devtools

让我们说有人在名为app.js的文件中写了这样的方法,试图对一个不存在的网址执行XHR请求:

app.controller('MainCtrl', function($scope,$http) {
  $scope.send = function() {
    $http.get('http://run.plnkr.co/thisIs404');
  };
});

我可以在控制台和网络面板中看到有关网址http://run.plnkr.co/thisis404的错误:

error in console

要调试这个,我想快速找到在源中进行此XHR调用的位置(即找到app.js文件):

所以我启用了chrome dev工具:

  • 调用堆栈中的异步调试
  • 调试任何XHR

调试器实际上在XHR请求上停止,但调用堆栈只显示对angular.js" core"的引用。文件:无法参考 app.js 可在任何地方找到

google chrome call stack

我尝试使用铬36和铬35.只有解决方案:在整个代码库中搜索错误的URL(在某些情况下可能很难)。

  • isn的异步调试模式是否应该指向堆栈中的app.js somwhere?
  • 有没有办法从控制台错误中轻松追踪这个app.js文件?

对于vanilla XHR请求(即没有角度),XHR调试调用堆栈在app.js中显示XHR调用(在这种情况下更容易调试):

enter image description here

此处的完整示例:http://plnkr.co/edit/lnCRpv?p=preview

[编辑] 正如我被问到的那样:Angular.js在我的测试中并没有缩小。

3 个答案:

答案 0 :(得分:11)

所以,你看,这个问题主要是因为angular的$ http很糟糕。对不起。

让我们尝试使用bluebird库,因为它提供了很长的堆栈跟踪。

Promise.longStackTraces();
Promise.resolve($http.get('...'));

您将获得以下堆栈跟踪:

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。)

最重要的一行是第一行:Possibly unhandled Error: [object Object]

是的。抛出一个对象,而不是真正的Error对象,并附加stack属性。作为参考,这里是如何抛出错误并保持其堆栈:https://github.com/Ralt/newerror/blob/master/index.js

那么,如何解决这个问题呢?这取决于几个决定:

  • 你想添加一个能够实现长堆栈跟踪的正确Promise吗?
  • 你想使用另一个抛出正确错误的xhr库吗?

如果您想添加真正的Promise lib,请使用bluebird。 AFAIK,它是为数不多的提供长堆栈跟踪的产品之一,也是最快的堆栈跟踪之一。

对于一个引起真正错误的正确的xhr库,我担心你在那里运气不好。编写一个支持您想要的浏览器的自定义版本并不是很难。由于没有IE8支持,这适用于(使用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。)

如您所见,堆栈跟踪信息丰富:

correct stack trace

答案 1 :(得分:1)

XHR请求堆叠在$http.pendingRequests数组中,稍后发送。这就是为什么您无法找到调用$http的位置与实际XHR请求的位置之间的直接链接。

如果您想知道哪个函数$http,您必须在$http函数中设置断点。

它打败了整个" XHR断点"在我看来的目的。

答案 2 :(得分:0)

我想到的一个选项是为$ http调试创建一个模块,您可以在需要调试$ http调用时将其作为依赖项添加到主模块中。可以注册$ http服务的装饰器,只需记录呼叫的参数,然后将其转发到$ http服务。还可以设置断点。

我创建了一个简单的工作示例here。我希望它会有所帮助。

示例$ http logger装饰器实现:

var httpDebugging = angular.module('http-debugging', []);

httpDebugging.decorator('$http', function ($delegate) {
  var debugAware = function (fnCallback) {
    return function () {
        var result = fnCallback.apply(this, arguments);    
        console.log('$http decorator: ', arguments);
        return result;
    };   
  }; 

  for(var prop in $delegate) {
    if (angular.isFunction($delegate[prop])) {
        $delegate[prop] = debugAware($delegate[prop]);
    }
  }

  return $delegate;
});