Я пытаюсь реализовать перехватчик для AngularJS (1.5.x), который может измерять все вызовы api и отправлять продолжительность каждого из них в Google Analytics.Как измерить длительность запросов (XHR) в AngularJS?
Я начал с фиктивной реализации этого, используя только new Date().getTime()
:
(function (angular) {
'use strict';
angular.module('MODULE')
.factory('HttpLoadingInterceptor', HttpLoadingInterceptor)
.config(HttpLoadingInterceptorConfig);
HttpLoadingInterceptor.$inject = ['$injector', '$q', 'AnalyticsService', '_'];
HttpLoadingInterceptorConfig.$inject = ['$httpProvider'];
function HttpLoadingInterceptor ($injector, $q, AnalyticsService, _) {
var REQUEST_GA_EVENT_NAME = 'REQUEST';
return {
request: request,
requestError: requestError,
response: response,
responseError: responseError
};
function request (config) {
config.requestTimestamp = now();
return config || $q.when(config);
}
function requestError (rejection) {
rejection.config.responseTimestamp = now();
trackRequest(rejection);
return $q.reject(rejection);
}
function response (response) {
response.config.responseTimestamp = now();
trackRequest(response);
return response || $q.when(response);
}
function responseError (rejection) {
rejection.config.responseTimestamp = now();
trackRequest(rejection);
return $q.reject(rejection);
}
function trackRequest (response) {
if (!_.startsWith(response.config.url, 'api')) {
return;
}
AnalyticsService.trackEvent(
REQUEST_GA_EVENT_NAME,
response.config.url,
response.status,
response.config.responseTimestamp - response.config.requestTimestamp
);
}
function now() {
return new Date().getTime();
}
}
function HttpLoadingInterceptorConfig ($httpProvider) {
$httpProvider.interceptors.push('HttpLoadingInterceptor');
}
})(window.angular);
Он хорошо выглядит на первый взгляд, но сравнивая продолжительность запросов от тех, кто собирается в закладке Networks в Chrome, я заметил, что те, что собраны в моем коде, всегда выше (иногда много!) Из тех, что собраны в Chrome.
Еще одна идея, которая пришла мне в голову, это использование Пользователь Судовождение API, поэтому я изменил мой код:
(function (angular, performance) {
'use strict';
angular.module('MODULE')
.factory('HttpLoadingInterceptor', HttpLoadingInterceptor)
.config(HttpLoadingInterceptorConfig);
HttpLoadingInterceptor.$inject = ['$injector', '$q', 'AnalyticsService', '_'];
HttpLoadingInterceptorConfig.$inject = ['$httpProvider'];
function HttpLoadingInterceptor ($injector, $q, AnalyticsService, _) {
var REQUEST_GA_EVENT_NAME = 'REQUEST';
var measureReqCnt = 1;
return {
request: request,
requestError: requestError,
response: response,
responseError: responseError
};
function request (config) {
if (shouldMeasure(config.url)) {
measureRequest(config);
}
return config || $q.when(config);
}
function requestError (rejection) {
if (shouldMeasure(rejection.config.url)) {
trackRequest(rejection);
}
return $q.reject(rejection);
}
function response (response) {
if (shouldMeasure(response.config.url)) {
trackRequest(response);
}
return response || $q.when(response);
}
function responseError (rejection) {
if (shouldMeasure(rejection.config.url)) {
trackRequest(rejection);
}
return $q.reject(rejection);
}
function shouldMeasure (url) {
return performance && _.startsWith(url, 'api');
}
function measureRequest (config) {
config.measureName = [config.url, measureReqCnt++].join('_');
config.markStartName = [config.measureName, 'start'].join('_');
config.markEndName = [config.measureName, 'end'].join('_');
performance.mark(config.markStartName);
}
function trackRequest (response) {
performance.mark(response.config.markEndName);
performance.measure(response.config.measureName, response.config.markStartName, response.config.markEndName);
var entries = performance.getEntriesByName(response.config.measureName, 'measure');
if (entries && entries.length) {
AnalyticsService.trackEvent(
REQUEST_GA_EVENT_NAME,
response.config.url,
response.status,
entries[0].duration
);
}
}
}
function HttpLoadingInterceptorConfig ($httpProvider) {
$httpProvider.interceptors.push('HttpLoadingInterceptor');
}
})(window.angular, window.performance);
.. но опять же я получил результаты, отличные от тех, собранные Chrome и даже за исключением тех, которые измеряются с использованием new Date().getTime()
Что я делаю неправильно? Как я должен делать это правильно? Может быть, API-интерфейс ресурса? AngularJS, конечно, накладывает немного.
Я не могу использовать метод API навигации пользователя - window.performacne.getEntries()
, чтобы найти длительность моих запросов, потому что я не могу распознать конкретный запрос. Параметры каждого запроса там недоступны, и у меня есть много одинаковых вызовов API с разными параметрами.
Должен ли я украсить собственный запрос XHR, который используется AngularJS?
Несомненно, я попробовал API производительности и получил тот же результат == Недействительный результат. Как я определил с Angular team, Angular дает нам свои собственные накладные расходы, поэтому измерение времени со всеми этими методами неэффективно. – mrzepinski
Если вы не хотите, чтобы какие-либо накладные расходы включались в ваши номера, я думаю, вам нужно найти способ использования 'performance.getEntries()' (или [PerformanceObserver] (https://developer.mozilla.org/ EN-US/Docs/Web/API/PerformanceObserver)). Кстати, я не знаю вашу точную цель с этим вызовом измерения, но вы уверены, что не хотите этого накладных расходов? Потому что это не просто накладные расходы на инфраструктуру, это может быть потому, что ваш ответ слишком велик и разбирается в том, что json требует времени. Я считаю, что это то, что вы должны измерить и заботиться. – inancsevinc