获取 $http 调用的完整调用堆栈跟踪
Posted
技术标签:
【中文标题】获取 $http 调用的完整调用堆栈跟踪【英文标题】:Get the full call stack trace of $http calls 【发布时间】:2014-08-13 10:06:33 【问题描述】:假设有人在名为 app.js
的文件中编写了这样的方法,试图针对不存在的 url 执行 XHR 请求:
app.controller('MainCtrl', function($scope,$http)
$scope.send = function()
$http.get('http://run.plnkr.co/thisIs404');
;
);
我可以在控制台和网络面板中看到有关 URL http://run.plnkr.co/thisis404
的错误:
为了调试它,我想快速找到这个 XHR 调用在源代码中的位置(即找到 app.js
文件):
所以我在 chrome 开发工具中启用:
调用堆栈中的异步调试 调试任何 XHR调试器实际上在 XHR 请求时停止,但调用堆栈只显示对 angular.js “核心”文件的引用:没有引用 app.js
任何地方都可以找到 .
我用 chromium 36 和 chrome 35 尝试了这个。唯一的解决方案:在整个代码库中搜索错误的 URL(在某些情况下可能很难做到)。
异步调试模式不应该指向堆栈中的app.js
somwhere 吗?
有没有办法从控制台错误中轻松追踪这个app.js
文件?
对于普通 XHR 请求(即没有角度),XHR 调试调用堆栈会在 app.js
中显示 XHR 调用(在这种情况下更容易调试):
此处为完整示例:http://plnkr.co/edit/lnCRpv?p=preview
[编辑] 正如我被问到的那样:Angular.js 在我的测试中没有被缩小。
【问题讨论】:
【参考方案1】:所以,你看,这个问题主要是因为 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 库,请使用 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.)
如您所见,堆栈跟踪信息丰富:
【讨论】:
是的,这个答案是正确的——这是因为 Bluebird 会进行未处理的拒绝跟踪,而 Angular 不会——请参阅This question,了解如何将 bluebird 与 AngularJS 一起使用。 AngularJS Promise 的堆栈跟踪非常糟糕,这使得在现实世界场景中使用它们非常困难。 我们可以修改angular的http函数来使用bluebird,这样它就可以在不修改现有项目的情况下工作吗?以下内容呢:plnkr.co/edit/1boCEqUjSLx8zGX2uqSo【参考方案2】:XHR 请求堆叠在$http.pendingRequests
数组中,稍后发送。这就是为什么在调用 $http
的位置和发出实际 XHR 请求的位置之间找不到直接联系的原因。
如果你想知道哪个函数调用了$http
,你必须在$http
函数中设置一个断点。
在我看来,这有点违背了整个“XHR 断点”的目的。
【讨论】:
【参考方案3】:我想到的一个选项是创建一个用于 $http 调试的模块,您可以在需要调试 $http 调用时将其作为依赖项添加到主模块中。可以注册 $http 服务的装饰器,它将简单地记录调用的参数并将其转发到 $http 服务。也可以设置断点。
我创建了一个简单的工作示例here。我希望它会有所帮助。
$http 记录器装饰器实现示例:
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;
);
【讨论】:
嗨,这给出了 $http 被调用的信息,这很有帮助,但是在 $http 函数上放置一个断点可以达到同样的效果。是否可以提取调用者(最好是行号,它启动了 $http 请求? 是的,购买在 console.log() 语句上添加断点,您可以在 javascript 调用堆栈上看到调用的第一个函数。 太棒了。我将使用 stacktracejs.com 更新它以包含整个调用堆栈 404 ajax 请求呢?你能得到导致它的代码行吗? 可能是的,通过将 $http 装饰器与拦截器结合使用。在拦截器中,您将获得响应代码。以上是关于获取 $http 调用的完整调用堆栈跟踪的主要内容,如果未能解决你的问题,请参考以下文章