Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 /**
      8  * @fileoverview This file provides a JavaScript helper function that
      9  * determines when network quiescence has been reached based on the time since
     10  * the last resource was received.
     11  */
     12 (function() {
     13 
     14   // Make executing this code idempotent.
     15   if (window.__telemetry_testHasReachedNetworkQuiescence) {
     16     return;
     17   }
     18 
     19   // Some benchmarks patch window.performance to make it deterministic.
     20   // Save the original performance object before it is patched.
     21   var real_performance = window.performance;
     22 
     23   // Set the Resource Timing interface functions that will be used below
     24   // to use whatever version is available currently regardless of vendor
     25   // prefix.
     26   real_performance.clearResourceTimings =
     27       (real_performance.clearResourceTimings     ||
     28        real_performance.mozClearResourceTimings  ||
     29        real_performance.msClearResourceTimings   ||
     30        real_performance.oClearResourceTimings    ||
     31        real_performance.webkitClearResourceTimings);
     32 
     33   real_performance.getEntriesByType =
     34       (real_performance.getEntriesByType     ||
     35        real_performance.mozGetEntriesByType  ||
     36        real_performance.msGetEntriesByType   ||
     37        real_performance.oGetEntriesByType    ||
     38        real_performance.webkitGetEntriesByType);
     39 
     40   // This variable will available to the function below and it will be
     41   // persistent across different function calls. It stores the last
     42   // entry in the list of PerformanceResourceTiming objects returned by
     43   // real_performance.getEntriesByType('resource').
     44   //
     45   // The reason for doing it this way is because the buffer for
     46   // PerformanceResourceTiming objects has a limit, and once it's full,
     47   // new entries are not added. We're only interested in the last entry,
     48   // so we can clear new entries when they're added.
     49   var lastEntry = null;
     50 
     51   // True when no resource has been loaded from the network for
     52   //|QUIESCENCE_TIMEOUT_MS| milliseconds. This value is sticky.
     53   var hasReachedQuiesence = false;
     54 
     55   // Time to wait before declaring network quiescence in milliseconds.
     56   var QUIESCENCE_TIMEOUT_MS = 2000;
     57 
     58   /**
     59    * This method uses the Resource Timing interface, which is described at
     60    * http://www.w3.org/TR/resource-timing/. It determines whether the time
     61    * since lodading any resources such as images and script files (including
     62    * resources requested via XMLHttpRequest) has exceeded a threshold defined
     63    # by |QUIESCENCE_TIMEOUT_MS|.
     64    *
     65    * @return {boolean} True if the time since either the load event, or the last
     66    *   resource was received after the load event exceeds the aforementioned
     67    *   threshold. This state is sticky, so once this function returns true for a
     68    *   given page, it will always return true.
     69    */
     70   window.__telemetry_testHasReachedNetworkQuiescence = function() {
     71     if (hasReachedQuiesence) {
     72       return true;
     73     }
     74 
     75     if (window.document.readyState !== 'complete') {
     76       return false;
     77     }
     78 
     79     var resourceTimings = real_performance.getEntriesByType('resource');
     80     if (resourceTimings.length > 0) {
     81       lastEntry = resourceTimings.pop();
     82       real_performance.clearResourceTimings();
     83     }
     84 
     85     // The times for performance.now() and in the PerformanceResourceTiming
     86     // objects are all in milliseconds since performance.timing.navigationStart,
     87     // so we must also get load time in the same terms.
     88     var timing = real_performance.timing;
     89     var loadTime = timing.loadEventEnd - timing.navigationStart;
     90     var lastResponseTimeMs = 0;
     91 
     92     // If there have been no resource timing entries, or the last entry was
     93     // before the load event, then use the time since the load event.
     94     if (!lastEntry || lastEntry.responseEnd < loadTime) {
     95       lastResponseTimeMs = real_performance.now() - loadTime;
     96     } else {
     97       lastResponseTimeMs = real_performance.now() - lastEntry.responseEnd;
     98     }
     99 
    100     if (lastResponseTimeMs >= QUIESCENCE_TIMEOUT_MS) {
    101       hasReachedQuiesence = true;
    102     }
    103 
    104     return hasReachedQuiesence;
    105   }
    106 
    107 })();
    108