当考虑 Web 性能指标时,需要关注的目标数字应该是从您自己的用户那里获得的实际用户指标。最常见的方法是利用 Splunk 之类的工具来分析您的机器数据,该工具支持您分析和可视化您的访问权限和错误日志。利用这些工具,您可以收集某些方面的性能数据,比如读取资产的文件 I/O 时间,以及 API 请求的访问时间。但是,您仍然需要推断客户端性能数据,将信号调用方在某些高级的检查点上,或者只利用类似 WebPagetest 的工具运行综合测试。现在,W3C 已将 API 标准化,用户可以通过使用 Performance 对象(该对象对于所有现代浏览器中的 Windows 对象而言是一个本机对象)捕获并报告浏览器内的性能数据。

捕获并报告浏览器内性能数据的 API

在 2010 年年末,万维网联盟 (W3C) 建立了一个新的工作组,即 Web 性能工作组,该工作组提供了用来测量用户代理特性和 API 的应用程序性能的各个方面的方法。该小组还开发了一个支持将浏览器暴露给 JavaScript 的 API,这是一个关键的 Web 性能指标。

在这个 API 中,该工作组创建了大量的新对象和事件,可量化性能指标和优化性能。总的说来,这些对象和界面包括:

  • Performance 对象:暴露多个对象,比如 PerformanceNavigationPerformanceTiming 和MemoryInfo,并能记录高精度时间(high resolution time),从而获得亚毫秒级计时。
  • Page Visibility API:使您能够确定某个给定页面是可见的还是隐藏的,从而能够优化动画的内存使用,或优化用于轮询操作的网络资源。

使用这些对象和界面捕获浏览器内的性能指标并将它们可视化。

Performance 对象

如果在 JavaScript 控制台中键入 window.performance,则会返回一个类型为 Performance 的对象,以及该对象所暴露的一些对象和方法。目前,标准的对象集包含:

  • window.performance.timing 用于类型 PerformanceTiming
  • window.performance.navigation 用于类型 PerformanceNavigation
  • window.performance.memory 用于类型 MemoryInfo(仅适用于 Chrome 浏览器)

图 1 显示了 Performance 对象的屏幕截图,可展开该对象来显示 PerformanceTiming 对象及其属性。

图 1. Performance 对象

Performance 对象被显示在控制台中,随它一起显示的还有展开的 PerformanceTiming 对象。

PerformanceTiming 对象

PerformanceTiming 对象是以公共属性的形式暴露的,在浏览器中执行检索和呈现内容的步骤中,它是一个关键指标。表 1 显示了与PerformanceTiming 对象中的每一个属性相对应的描述。

表 1. PerformanceTiming 对象属性
对象属性 描述
navigationStart 在导航开始的时候、在浏览器开始卸载前一页(如果有这样的页面)的时候,或者在开始提取内容的时候,捕获所需的数据。它将包含 unloadEventStart 数据或 fetchStart 数据。要想跟踪端到端的时间,可从使用这个值开始。
unloadEventStartunloadEventEnd 在浏览器开始卸载前一页或已完成前一页的卸载的时候,捕获所需的数据(如果相同域中有前一页需要卸载的话)。
domainLookupStartdomainLookupEnd 在浏览器开始和完成针对所请求内容的 DNS 查找时,捕获所需的数据。
redirectStart/redirectEnd 在浏览器开始和完成任何 HTTP 重定向时捕获所需的数据。
connectStart/connectEnd 在浏览器开始和完成建立当前页面的远程服务器 TCP 连接时捕获所需的数据。
fetchStart 在浏览器首次开始检查用于所请求资源的缓存时捕获所需的数据。
requestStart 在浏览器通过发送 HTTP 请求来获得所请求的资源时捕获所需的数据。
responseStart/responseEnd 在浏览器首次进行注册并完成注册收到服务器响应时捕获所需的数据。
domLoading/domComplete 在文档开始和完成加载时捕获所需的数据。
domContentLoadedEventEnd/domContentLoadedEventStart 在文档的 DOMContentLoaded 开始和完成加载时捕获所需的数据,这相当于浏览器已完成所有内容的加载并运行页面中包含的所有脚本。
domInteractive 在页面的 Document.readyState 属性变为 interactive 时捕获所需的数据,这会导致触发 readystatechange 事件。
loadEventStart/loadEventEnd 在加载事件触发前和加载事件触发后立刻捕获所需的数据。

要想将上述步骤及其相应内容的顺序更好地可视化,请参见图 2。

图 2. 可视化 PerformanceTiming 属性的顺序

 

Performance 导航

图 3 显示了包含已展开的 PerformanceNavigation 对象的 Performance 对象。

图 3. PerformanceNavigation 对象

请注意,导航对象有两个只读属性:redirectCount 和 type。顾名思义,redirectCount 属性是 HTTP 重定向的数量,浏览器根据它们来获取当前页面。

HTTP 重定向是 Web 性能的一个重要因素,因为它们会导致每一次重定向都需要执行一次完整的 HTTP 往返过程。原始请求是从 Web 服务器返回的,作为包含新位置路径的 301 或 302。然后,浏览器必须初始化一个新的 TCP 连接,并发送一个新请求来获得新位置。这一附加步骤为原始资源请求增加了额外的延迟。

redirectCount 属性如清单 1 所示。

清单 1. 访问 redirectCount 属性
  1. >>> performance.navigation.redirectCount
  2. 0

导航对象的另一个属性是 typenavigation.type 属性是用下列常量表示的 4 个值中的一个:

  • TYPE_NAVIGATE 的值为 0,表示可通过单击一个链接、提交表单或直接在地址栏中输入 URL 导航到当前页面。
  • TYPE_RELOAD 的值为 1,表示通过重载操作到达当前页面。
  • TYPE_BACK_FORWARD 的值为 2,表示通过使用浏览器历史记录、使用 back 或 forward 按钮、以编程方式,或者通过浏览器的历史对象来导航到页面。
  • TYPE_RESERVED 的值为 255,它是其他任何导航类型的全方位指示。

信息汇总

要想使用这些对象来捕获和可视化客户端性能指标,可先创建一个 JavaScript 库,收集 PerformanceTiming 数据,并将这些数据发送到某个端点进行收集和分析。查看这个 JavaScript 库,该库恰好用于完成这项工作。

perfLogger.js 脚本使用了 Performance 对象。创建一个名为 perfLogger 的命名空间,并声明一些局部变量来保存根据 PerformanceTiming 属性推测的值。

您可以通过使用这些示例和下面这些模式来计算时间:

  • 要计算认知时间(perceived time) — 从 timing.navigationStart 中减去当前时间。
  • 要计算到达页面过程中所经历的所有重定向时间 — 从 timing.redirectStart 中减去 timing.redirectEnd
  • 要想获得执行 DNS 查找所用的时间 — 从 timing.domainLookupStart 中减去 timing.domainLookupEnd,要想获得呈现页面所用的时间,请从 xs 中减去当前时间。

声明并初始化局部变量后,使用 public getter 函数从命名空间暴露它们,如清单 2 所示。

清单 2. 暴露 public getter 函数的局部变量
  1. var perfLogger = function(){
  2. var serverLogURL = "/lib/savePerfData.php",
  3. loggerPool = [],
  4. _pTime = Date.now() - performance.timing
  5. .navigationStart || 0,
  6. _redirTime = performance.timing.redirectEnd
  7. - performance.timing.redirectStart || 0,
  8. _cacheTime = performance.timing.domainLookupStart
  9. - performance.timing.fetchStart || 0,
  10. _dnsTime = performance.timing.domainLookupEnd
  11. - performance.timing.domainLookupStart || 0,
  12. _tcpTime = performance.timing.connectEnd
  13. - performance.timing.connectStart || 0,
  14. _roundtripTime = performance.timing.responseEnd
  15. - performance.timing.connectStart || 0,
  16. _renderTime = Date.now() - performance.timing
  17. .domLoading || 0;
  18.  
  19. //expose derived performance data
  20. perceivedTime: function(){
  21. return _pTime;
  22. },
  23. redirectTime: function(){
  24. _redirTime;
  25. },
  26. cacheTime: function(){
  27. return _cacheTime;
  28. },
  29. dnsLookupTime: function(){
  30. return _dnsTime;
  31. },
  32. tcpConnectionTime: function(){
  33. return _tcpTime;
  34. },
  35. roundTripTime: function(){
  36. return _roundtripTime;
  37. },
  38. pageRenderTime: function(){
  39. return _renderTime;
  40. },
  41.  
  42. }

您可以从命名空间访问属性,如清单 3 所示。

清单 3. 从命名空间访问属性
  1. perfLogger.pageRenderTime
  2. perfLogger. roundTripTime
  3. perfLogger. tcpConnectionTime
  4. perfLogger. dnsLookupTime
  5. perfLogger. cacheTime
  6. perfLogger. redirectTime
  7. perfLogger. perceivedTime

在命名空间中,函数 logToServer 将指标重新写回您在变量 serverLogURL 中定义的端点,如清单 4 所示。

清单 4. logToServer 函数
  1. function logToServer(id){
  2. var params = "data=" + JSON.stringify(jsonConcat
  3. (loggerPool[id],TestResults.prototype));
  4. console.log(params)
  5. var xhr = new XMLHttpRequest();
  6. xhr.open("POST", serverLogURL, true);
  7. xhr.setRequestHeader("Content-type",
  8. "application/x-www-form-urlencoded");
  9. xhr.setRequestHeader("Content-length", params.length);
  10. xhr.setRequestHeader("Connection", "close");
  11. xhr.onreadystatechange = function()
  12. {
  13. if (xhr.readyState==4 && xhr.status==200)
  14. {
  15. console.log('log written');
  16. }
  17. };
  18. xhr.send(params);
  19. }

perfLogger.js 库还提供了一些基准测试功能,您可以在其中测试 JavaScript 的专用数据块,甚至可以运行一组花费 N 时间量的测试来执行真正的基准测试。

perfLogger.js 库的完整源代码如清单 5 所示。

清单 5. perfLogger.js 库的完整源代码
  1. var perfLogger = function(){
  2. var serverLogURL = "/lib/savePerfData.php",
  3. loggerPool = [],
  4. _pTime = Date.now() - performance.timing.navigationStart
  5. || 0,
  6. _redirTime = performance.timing.redirectEnd
  7. - performance.timing.redirectStart || 0,
  8. _cacheTime = performance.timing.domainLookupStart
  9. - performance.timing.fetchStart || 0,
  10. _dnsTime = performance.timing.domainLookupEnd
  11. - performance.timing.domainLookupStart || 0,
  12. _tcpTime = performance.timing.connectEnd
  13. - performance.timing.connectStart || 0,
  14. _roundtripTime = performance.timing.responseEnd
  15. - performance.timing.connectStart || 0,
  16. _renderTime = Date.now() - performance.timing.domLoading
  17. || 0;
  18.  
  19. function TestResults(){};
  20. TestResults.prototype.perceivedTime = _pTime;
  21. TestResults.prototype.redirectTime = _redirTime;
  22. TestResults.prototype.cacheTime = _cacheTime;
  23. TestResults.prototype.dnsLookupTime = _dnsTime;
  24. TestResults.prototype.tcpConnectionTime = _tcpTime;
  25. TestResults.prototype.roundTripTime = _roundtripTime;
  26. TestResults.prototype.pageRenderTime = _renderTime;
  27.  
  28. function jsonConcat(object1, object2) {
  29. for (var key in object2) {
  30. object1[key] = object2[key];
  31. }
  32. return object1;
  33. }
  34.  
  35. function calculateResults(id){
  36. loggerPool[id].runtime = loggerPool[id].stopTime
  37. - loggerPool[id].startTime;
  38. }
  39.  
  40. function setResultsMetaData(id){
  41. loggerPool[id].url = window.location.href;
  42. loggerPool[id].useragent = navigator.userAgent;
  43. }
  44.  
  45. function drawToDebugScreen(id){
  46. var debug = document.getElementById("debug")
  47. var output = formatDebugInfo(id)
  48. if(!debug){
  49. var divTag = document.createElement("div");
  50. divTag.id = "debug";
  51. divTag.innerHTML = output
  52. document.body.appendChild(divTag);
  53. }else{
  54. debug.innerHTML += output
  55. }
  56. }
  57.  
  58. function logToServer(id){
  59. var params = "data=" + JSON.stringify(jsonConcat(
  60. loggerPool[id],TestResults.prototype));
  61. console.log(params)
  62. var xhr = new XMLHttpRequest();
  63. xhr.open("POST", serverLogURL, true);
  64. xhr.setRequestHeader("Content-type",
  65. "application/x-www-form-urlencoded");
  66. xhr.setRequestHeader("Content-length", params.length);
  67. xhr.setRequestHeader("Connection", "close");
  68. xhr.onreadystatechange = function()
  69. {
  70. if (xhr.readyState==4 && xhr.status==200)
  71. {
  72. //console.log(xhr.responseText);
  73. }
  74. };
  75. xhr.send(params);
  76. }
  77.  
  78. function formatDebugInfo(id){
  79. var debuginfo = "<p><strong>"
  80. + loggerPool[id].description + "</strong><br/>";
  81. if(loggerPool[id].avgRunTime){
  82. debuginfo += "average run time: " + loggerPool[id]
  83. .avgRunTime + "ms<br/>";
  84. }else{
  85. debuginfo += "run time: " + loggerPool[id].runtime
  86. + "ms<br/>";
  87. }
  88. debuginfo += "path: " + loggerPool[id].url
  89. + "<br/>";
  90. debuginfo += "useragent: " + loggerPool[id].useragent
  91. + "<br/>";
  92.  
  93. debuginfo += "Perceived Time: " +
  94. loggerPool[id].perceivedTime + "<br/>";
  95. debuginfo += "Redirect Time: " +
  96. loggerPool[id].redirectTime + "<br/>";
  97. debuginfo += "Cache Time: " +
  98. loggerPool[id].cacheTime + "<br/>";
  99. debuginfo += "DNS Lookup Time: " +
  100. loggerPool[id].dnsLookupTime + "<br/>";
  101. debuginfo += "tcp Connection Time: " +
  102. loggerPool[id].tcpConnectionTime + "<br/>";
  103. debuginfo += "roundTripTime: "+
  104. loggerPool[id].roundTripTime + "<br/>";
  105. debuginfo += "pageRenderTime: " +
  106. loggerPool[id].pageRenderTime + "<br/>";
  107. debuginfo += "</p>";
  108. return debuginfo
  109. }
  110.  
  111. return {
  112. startTimeLogging: function(id, descr,drawToPage
  113. ,logToServer){
  114. loggerPool[id] = new TestResults();
  115. loggerPool[id].id = id;
  116. loggerPool[id].startTime = performance.now();
  117. loggerPool[id].description = descr;
  118. loggerPool[id].drawtopage = drawToPage;
  119. loggerPool[id].logtoserver = logToServer
  120. },
  121.  
  122. stopTimeLogging: function(id){
  123. loggerPool[id].stopTime = performance.now();
  124. calculateResults(id);
  125. setResultsMetaData(id);
  126. if(loggerPool[id].drawtopage){
  127. drawToDebugScreen(id);
  128. }
  129. if(loggerPool[id].logtoserver){
  130. logToServer(id);
  131. }
  132. },
  133.  
  134. logBenchmark: function(id, timestoIterate, func, debug, log){
  135. var timeSum = 0;
  136. for(var x = 0; x < timestoIterate; x++){
  137. perfLogger.startTimeLogging(id, "benchmarking "+ func,
  138. false, false);
  139. func();
  140. perfLogger.stopTimeLogging(id)
  141. timeSum += loggerPool[id].runtime
  142. }
  143. loggerPool[id].avgRunTime = timeSum/timestoIterate
  144. if(debug){
  145. drawToDebugScreen(id)
  146. }
  147. if(log){
  148. logToServer(id)
  149. }
  150. },
  151.  
  152. //expose derived performance data
  153. perceivedTime: function(){
  154. return _pTime;
  155. },
  156. redirectTime: function(){
  157. _redirTime;
  158. },
  159. cacheTime: function(){
  160. return _cacheTime;
  161. },
  162. dnsLookupTime: function(){
  163. return _dnsTime;
  164. },
  165. tcpConnectionTime: function(){
  166. return _tcpTime;
  167. },
  168. roundTripTime: function(){
  169. return _roundtripTime;
  170. },
  171. pageRenderTime: function(){
  172. return _renderTime;
  173. },
  174.  
  175. showPerformanceMetrics: function(){
  176. this.startTimeLogging("no_id", "draw perf data to page"
  177. ,true,true);
  178. this.stopTimeLogging("no_id");
  179.  
  180. }
  181.  
  182. }
  183. }();
  184.  
  185. performance.now = (function() {
  186. return performance.now ||
  187. performance.mozNow ||
  188. performance.msNow ||
  189. performance.oNow ||
  190. performance.webkitNow ||
  191. function() { return new Date().getTime(); };
  192. })();

实现和可视化

要想使用 perfLogger.js 脚本可视化浏览器内的性能,可以将该脚本嵌入页面中,在页面的 onload 事件上,您可以将性能数据推送回端点,将它们保存为一个平面文件。GitHub 中的 perfLogger 项目附带了一个 PHP 脚本,名为 savePerfData.php,该脚本恰好提供了此功能。该文件的源代码如清单 6 所示。

清单 6. savePerfData.php 的源代码
  1. <?php
  2. require("util/fileio.php");
  3.  
  4. $logfile = "log/runtimeperf_results.txt";
  5. $benchmarkResults = formatResults($_POST["data"]);
  6.  
  7. saveLog($benchmarkResults, $logfile);
  8.  
  9. function formatResults($r){
  10. print_r($r);
  11. $r = stripcslashes($r);
  12. $r = json_decode($r);
  13. if(json_last_error() > 0){
  14. die("invalid json");
  15. }
  16. return($r);
  17. }
  18.  
  19. function formatNewLog($file){
  20. $headerline = "IP, TestID, StartTime, StopTime, RunTime,
  21. URL, UserAgent, PerceivedLoadTime, PageRenderTime, RoundTripTime,
  22. TCPConnectionTime, DNSLookupTime, CacheTime, RedirectTime";
  23. appendToFile($headerline, $file);
  24. }
  25.  
  26. function saveLog($obj, $file){
  27. if(!file_exists($file)){
  28. formatNewLog($file);
  29. }
  30. $obj->useragent = cleanCommas($obj->useragent);
  31. $newLine = $_SERVER["REMOTE_ADDR"] . "," . $obj->id .","
  32. . $obj->startTime . "," . $obj->stopTime . "," . $obj->runtime . ","
  33. . $obj->url . "," . $obj->useragent . $obj->perceivedTime . ","
  34. . $obj->pageRenderTime . "," . $obj->roundTripTime . ","
  35. . $obj->tcpConnectionTime . "," . $obj->dnsLookupTime . ","
  36. . $obj->cacheTime . "," . $obj->redirectTime;
  37. appendToFile($newLine, $file);
  38. }
  39.  
  40. function cleanCommas($data){
  41. return implode("", explode(",", $data));
  42. }
  43.  
  44. ?>

这个 PHP 实际上将 perfLogger.js 发送的 POST 数据保存为一个平面文件,格式如清单 7 所示。

清单 7. perfLogger.js 发送的 POST 数据
  1. IP, TestID, StartTime, StopTime, RunTime, URL, UserAgent,
  2. PerceivedLoadTime, PageRenderTime, RoundTripTime, TCPConnectionTime,
  3. DNSLookupTime, CacheTime, RedirectTime
  4. 75.149.106.130,page_render,1341243219599,1341243220218,619
  5. ,http://www.tom-barker.com/blog/?p=x,Mozilla/5.0 (Macintosh;
  6. Intel Mac OS X 10.5; rv:13.0) Gecko/20100101
  7. Firefox/13.0.1790,261,-2,36,0,-4,0

此时此刻,您可以看到有一些很好的数据点值得关注,例如:

  • 用户代理所用的平均加载时间
  • 在平均加载时间方面,HTTP 事务流程的哪一部分所用的时间最多
  • 总体的加载时间分布

在 GitHub 存储库中,还有一个 R 脚本,名为 runtimePerformance.R,该脚本将会摄取您生成的这个日志文件,并实现数据可视化(参见清单 8)。

清单 8. 名为 runtimePerformance.R 的 R 脚本
  1. dataDirectory <- "/Applications/MAMP/htdocs/lab/log/"
  2. chartDirectory <- "/Applications/MAMP/htdocs/lab/charts/"
  3. testname = "page_render"
  4.  
  5. perflogs <- read.table(paste(dataDirectory, "runtimeperf
  6. _results.csv", sep=""), header=TRUE, sep=",")
  7. perfchart <- paste(chartDirectory, "runtime_",testname, ".
  8. pdf", sep="")
  9.  
  10. loadTimeDistrchart <- paste(chartDirectory,
  11. "loadtime_distribution.pdf", sep="")
  12. requestBreakdown <- paste(chartDirectory,
  13. "avgtime_inrequest.pdf", sep="")
  14. loadtime_bybrowser <- paste(chartDirectory,
  15. "loadtime_bybrowser.pdf", sep="")
  16.  
  17. pagerender <- perflogs[perflogs$TestID == "page_render",]
  18. df <- data.frame(pagerender$UserAgent, pagerender$RunTime)
  19. df <- by(df$pagerender.RunTime, df$pagerender.UserAgent, mean)
  20. df <- df[order(df)]
  21.  
  22. pdf(perfchart, width=10, height=10)
  23. opar <- par(no.readonly=TRUE)
  24. par(las=1, mar=c(10,10,10,10))
  25. barplot(df, horiz=TRUE)
  26. par(opar)
  27. dev.off()
  28.  
  29. getDFByBrowser<-function(data, browsername){
  30. return(data[grep(browsername, data$UserAgent),])
  31. }
  32.  
  33. printLoadTimebyBrowser <- function(){
  34. chrome <- getDFByBrowser(perflogs, "Chrome")
  35. firefox <- getDFByBrowser(perflogs, "Firefox")
  36. ie <- getDFByBrowser(perflogs, "MSIE")
  37.  
  38. meanTimes <- data.frame(mean(chrome$PerceivedLoadTime),
  39. mean(firefox$PerceivedLoadTime), mean(ie$PerceivedLoadTime))
  40. colnames(meanTimes) <- c("Chrome", "Firefox",
  41. "Internet Explorer")
  42. pdf(loadtime_bybrowser, width=10, height=10)
  43. barplot(as.matrix(meanTimes), main="Average Perceived Load
  44. Time\nBy Browser", ylim=c(0, 600), ylab="milliseconds")
  45. dev.off()
  46. }
  47.  
  48. pdf(loadTimeDistrchart, width=10, height=10)
  49. hist(perflogs$PerceivedLoadTime, main="Distribution of
  50. Perceived
  51. Load Time", xlab="Perceived Load Time in Milliseconds",
  52. col=c("#CCCCCC"))
  53. dev.off()
  54.  
  55. avgTimeBreakdownInRequest <- function(){
  56.  
  57. #expand exponential notation
  58. options(scipen=100, digits=3)
  59.  
  60. #set any negative values to 0
  61. perflogs$PageRenderTime[perflogs$PageRenderTime < 0] <- 0
  62. perflogs$RoundTripTime[perflogs$RoundTripTime < 0] <- 0
  63. perflogs$TCPConnectionTime[perflogs$TCPConnectionTime < 0] <- 0
  64. perflogs$DNSLookupTime[perflogs$DNSLookupTime < 0] <- 0
  65.  
  66. #capture avg times
  67. avgTimes <- data.frame(mean(perflogs$PageRenderTime),
  68. mean(perflogs$RoundTripTime), mean(perflogs$TCPConnectionTime),
  69. mean(perflogs$DNSLookupTime))
  70. colnames(avgTimes) <- c("PageRenderTime", "RoundTripTime",
  71. "TCPConnectionTime", "DNSLookupTime")
  72. pdf(requestBreakdown, width=10, height=10)
  73. opar <- par(no.readonly=TRUE)
  74. par(las=1, mar=c(10,10,10,10))
  75. barplot(as.matrix(avgTimes), horiz=TRUE, main="Average Time
  76. Spent\nDuring HTTP Request", xlab="Milliseconds")
  77. par(opar)
  78. dev.off()
  79.  
  80. }
  81.  
  82. printLoadTimebyBrowser()
  83. avgTimeBreakdownInRequest()

这个 R 脚本附带了一些内置的功能,例如 printLoadTimebyBrowser 和 avgTimeBreakdownInRequest。图 4 是 printLoadTimebyBrowser 输出的屏幕截图。

图 4. printLoadTimebyBrowser 的输出

图 5 是 avgTimeBreakdownInRequest 的屏幕截图。

图 5. avgTimeBreakdownInRequest 代码的输出code

在将性能数据加载到 R 会话中之后,所有已摄取的数据指标都存储在一个名为 perflogs 的数据帧内,这样您就可以访问单独的列,如清单 9 所示。

清单 9. 已摄取的指标存储在名为 perflogs 的数据帧内
  1. perflogs$PerceivedLoadTime
  2. perflogs$ PageRenderTime
  3. perflogs$RoundTripTime
  4. perflogs$TCPConnectionTime
  5. perflogs$DNSLookupTime
  6. perflogs$UserAgent

该代码支持您开始执行一些探索性的数据分析,比如创建柱状图来查看用户群的感知加载时间的分布,如清单 10 所示。

清单 10. 用户群的感知加载时间
  1. hist(perflogs$PerceivedLoadTime, main="Distribution of
  2. Perceived Load Time", xlab="Perceived Load Time in Milliseconds",
  3. col=c("#CCCCCC"))
  4. dev.off()

图 6 显示了用户群的感知加载时间分布柱状图。

图 6. 用户群的感知加载时间分布柱状图

结束语

本文帮助您更好地了解了 Performance 对象中一些功能,并模拟了如何使用可从该对象收集的浏览器内指标。通过这里介绍的模型,您可以从实际用户群中捕获真正的用户指标,这是您可以收集并跟踪的最有价值的性能指标类型。

如果愿意的话,您还可以使用该模型中的 perfLogger.js 和所有实用程序文件。您可以随时发表您自己的意见以及对该项目的更改。

源文链接

使用 W3C Performance 对象通过 R 和 JavaScript 将浏览器内的性能数据可视化[转]的更多相关文章

  1. JavaScript使用浏览器内置XML解析器解析DOM对象

    所有现代浏览器都内建了供读取和操作 XML 的 XML 解析器.解析器把 XML 转换为 XML DOM 对象 (可通过 JavaScript 操作的对象). 一.获取DOM对象 XMLHttpReq ...

  2. JavaScript使用浏览器内置XMLHttpRequest对象执行Ajax请求

    所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject).XMLHttpRequest 用于在后台与服务器交换数据.这意味着可以在不重新加载整个 ...

  3. 4款开源免费的数据可视化JavaScript库

    概述:交互式数据可视化在很大程度上取决于JavaScript库的任务能力.在这篇文章中,我们将看看四个JavaScript库:D3,InfoVis,Processing.js,和Recline.js. ...

  4. web计时机制——performance对象

    前面的话 页面性能一直都是Web开发人员最关注的领域.但在实际应用中,度量页面性能的指标,是提高代码复杂程度和巧妙地使用javascript的Date对象.Web Timing API改变了这个局面, ...

  5. [转]web计时机制——performance对象

    页面性能一直都是Web开发人员比较关注的领域.但在实际应用中,度量页面性能的指标,是javascript的Date对象.Web Timing API改变了这个局面,让开发人员通过javascript就 ...

  6. JavaScript学习07 内置对象

    JavaScript内置对象 图像对象 导航对象 窗口对象 屏幕对象 事件对象 历史对象 文件对象(重要) 锚点对象 链接对象 框架对象 表单对象(重要) 位置对象 JS Window 窗口对象:ht ...

  7. javascript中的内置对象

    2015.12.1 javascript中的内置对象 复习: 1.js中的内置函数 alert prompt write parseInt parseFloat eval isNaN document ...

  8. JavaScript 3种内置对象

    前面我们学了对象,如何创建对象及使用对象. 内置对象不需要实例化,就可以使用. 可以通俗地理解,在内存里的东东是对象,也就是实例化好的.在磁盘里的东东是类,需要实例化才能使用.实例化后的东东在内存里. ...

  9. javaScript中Math内置对象基本方法入门

    概念 Math 是javaScript的内置对象,包含了部分数学常数属性和数学函数方法. Math 不是一个函数对象,用户Number类型进行使用,不支持BigInt. Math 的所有属性与方法都是 ...

随机推荐

  1. inventor安装失败怎样卸载安装inventor 2019?

    AUTODESK系列软件着实令人头疼,安装失败之后不能完全卸载!!!(比如maya,cad,3dsmax等).有时手动删除注册表重装之后还是会出现各种问题,每个版本的C++Runtime和.NET f ...

  2. 连接虚机中的mysql服务

    1:修改mysql库中的user表的root用户的host值为% 2:授权:在mysql命令中执行 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFI ...

  3. NASM在Ubuntu上的安装与简单使用

    一 .安装NASM 1. 下载安装文件 地址是:http://www.nasm.us/pub/nasm/releasebuilds/2.11.08/ 2.解压(具体命令要根据压缩包的类型来选用) 3. ...

  4. mustache语法 转自小花大方

    mustache语法 mustache 模板,用于构造html页面内容.在实际工作中,当同一个模板中想要调用不同的函数来渲染画面,在已经自定义好了的前提下,可以在渲染页面时对传入的参数进行手动判断.[ ...

  5. IIS下不能下载文件的docx文档,XLSX文档的设置方法(转)

    IIS下不能下载文件的docx文档,XLSX文档的设置方法 Office 2007的的界面风格默认格式中都是.DOCX,XLSX,PPTX等等后缀,连结中包含此类文件时,界面风格默认什么打不开的其实只 ...

  6. 卸载jrebel

    Setting-Plugins-搜索Jrebel-右击选择Uninstall-apply 确认重启idea即可

  7. hdu 3586 最小代价切断根与叶子联系

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3586 http://blog.csdn.net/woshi250hua/article/details ...

  8. hibernate课程 初探一对多映射2-1 一对多映射简介

    1 在数据库中用主外键的形式实现一对多的映射关系 2 hibernate 在一方设置集合set,表示多方

  9. Android监听安装卸载

    需要通过receiver来监听: 在AndroidManifest.xml文件中注册的receiver中必须加上<data android:scheme="package"/ ...

  10. nginx配置优化-生产环境应用版

    user www www; worker_processes auto; worker_cpu_affinity auto; error_log /usr/local/nginx/logs/error ...