Получить трассировку стека вызовов вызовов $http
Скажем, кто-то написал метод, подобный этому, в файле под названием app.js
, который пытается отобразить запрос XHR angainst не существующего url:
app.controller('MainCtrl', function($scope,$http) {
$scope.send = function() {
$http.get('http://run.plnkr.co/thisIs404');
};
});
Я вижу ошибку в отношении URL http://run.plnkr.co/thisis404
в консоли и на панели сети:
![error in console]()
Чтобы отладить это, я хочу быстро найти этот вызов XHR в источниках (т.е. найти файл app.js
):
Итак, я включаю в хром dev tools:
- асинхронная отладка в стеке вызовов
- отладить любой XHR
Отладчик фактически останавливается на запросе XHR, но в стеке вызовов отображаются ссылки на файлы angular.js: ссылка на app.js
в любом месте, где можно найти strong > .
![google chrome call stack]()
Я попробовал это с хромом 36 и хром 35. Только решение: поиск неправильного URL-адреса во всей базе кода (что в некоторых случаях может быть трудным).
- Не должен ли режим отладки async указывать на
app.js
somwhere в стеке?
- Есть ли способ легко отследить этот
app.js
файл из-за ошибки консоли?
С помощью запросов ванильного XHR (т.е. без angular), стек XHR-отладки вызывает вызов XHR в app.js
(который в этом случае легче отлаживать):
![enter image description here]()
Полный пример здесь: http://plnkr.co/edit/lnCRpv?p=preview
[EDIT]
Как я уже спросил: 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 здесь.)
Самая важная строка - первая: Possibly unhandled Error: [object Object]
.
Угу. Объект бросается, а не реальный объект Error
, с прикрепленным к нему свойством stack
. Для справки, вот как сделать ошибку и сохранить ее стек вместе с ней: https://github.com/Ralt/newerror/blob/master/index.js
Итак, как это исправить? Это зависит от нескольких решений:
- Вы хотите добавить правильную библиотеку Promise, которая позволяет отслеживать длинные стеки?
- Вы хотите использовать другую xhr lib, которая порождает правильные ошибки?
Если вы хотите добавить настоящую Promise lib, используйте bluebird. AFAIK, это один из немногих, который обеспечивает длинные трассировки стека, и он самый быстрый из них.
Для правильного xhr lib, который порождает реальные ошибки, я боюсь, что вам там не повезло. Написание пользовательского с поддержкой браузеров, которые вы хотите, на самом деле не очень сложно. Без поддержки 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 здесь.)
Как вы можете видеть, трассировка стека информативна:
![correct stack trace]()
Ответ 2
Запросы XHR сложены в массив $http.pendingRequests
и отправляются позже. Вот почему вы не можете найти прямую связь между тем, где вызывается $http
и где выполняется фактический запрос XHR.
Если вы хотите узнать, какая функция называется $http
, вам нужно установить точку останова в $http
.
Похоже на то, что поражение цели "точки останова XHR" на мой взгляд.
Ответ 3
Один из вариантов, который пришел мне на ум, - создать модуль для отладки $http, который вы можете добавить в зависимости от вашего основного модуля, когда вам нужно отлаживать $http-вызовы. Там может быть зарегистрирован декоратор для службы $http, который будет просто регистрировать аргументы вызова, пересылать его в службу $http. Там также может быть установлена точка останова.
Я создал простой рабочий пример здесь. Надеюсь, это поможет.
Пример реализации декодера $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;
});