1

Я пытаюсь реализовать перехватчик для 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?

ответ

0

Как насчет повышения производительности.now()? (https://developer.mozilla.org/en-US/docs/Web/API/Performance/now), который предназначен для высокоточного отслеживания производительности по сравнению с датой()?

См: performance.now() vs Date.now()

Кроме того, вы заботитесь об абсолютных цифрах? Для отслеживания производительности иногда относительный является лучшим, поскольку сравнение яблок с апельсинами редко дает реальную дату-точку.

Мое предположение - есть только расхождение между тем, что используется таймером, а также точками, когда время было занято. Инструменты Chrome Dev, вероятно, гораздо ближе к «проводу», чем с кодом приложения. Если это помогает, у нас также есть инструмент для анализа и отладки API (www.moesif.com/features), но полное раскрытие информации о том, что я являюсь генеральным директором.

+0

Несомненно, я попробовал API производительности и получил тот же результат == Недействительный результат. Как я определил с Angular team, Angular дает нам свои собственные накладные расходы, поэтому измерение времени со всеми этими методами неэффективно. – mrzepinski

+0

Если вы не хотите, чтобы какие-либо накладные расходы включались в ваши номера, я думаю, вам нужно найти способ использования 'performance.getEntries()' (или [PerformanceObserver] (https://developer.mozilla.org/ EN-US/Docs/Web/API/PerformanceObserver)). Кстати, я не знаю вашу точную цель с этим вызовом измерения, но вы уверены, что не хотите этого накладных расходов? Потому что это не просто накладные расходы на инфраструктуру, это может быть потому, что ваш ответ слишком велик и разбирается в том, что json требует времени. Я считаю, что это то, что вы должны измерить и заботиться. – inancsevinc

Смежные вопросы