diff --git a/app/node_views/results.html b/app/node_views/results.html index 25708cf..eeffda8 100644 --- a/app/node_views/results.html +++ b/app/node_views/results.html @@ -116,6 +116,33 @@
+

Javascript Spaghetti Timeline

+

+ This graph gives a quick view of when the Javascript interactions with the DOM occur during the loading of the page. +

+
+
+
+
+
+
+
+
DOM creation
+
DOM content loaded event
+
Page completion
+
Page completed
+
+
+

Javascript Spaghetti Profiler

The table below shows the interactions between Javascript and the DOM. It is usefull to understand what's going on when the page loads. diff --git a/app/public/scripts/resultsCtrl.js b/app/public/scripts/resultsCtrl.js index cf687ca..b7c0f17 100644 --- a/app/public/scripts/resultsCtrl.js +++ b/app/public/scripts/resultsCtrl.js @@ -215,6 +215,56 @@ app.controller('ResultsCtrl', function ($scope) { function initExecutionView() { $scope.slowRequestsOn = false; $scope.slowRequestsLimit = 5; + + + // Now read the tree and display it on a timeline + + // Split the timeline into 200 intervals + var numberOfIntervals = 200; + var lastEvent = $scope.javascript.children[$scope.javascript.children.length - 1]; + var endTime = lastEvent.data.timestamp + (lastEvent.data.time || 0); + $scope.timelineIntervalDuration = endTime / numberOfIntervals; + + // Pre-filled array of 100 elements + $scope.timeline = Array.apply(null, new Array(numberOfIntervals)).map(Number.prototype.valueOf,0); + + treeRunner($scope.javascript, function(node) { + + if (node.data.time) { + + // If a node is between two intervals, split it. That's the meaning of the following dirty algorithm. + + var startInterval = Math.floor(node.data.timestamp / $scope.timelineIntervalDuration); + var endInterval = Math.floor((node.data.timestamp + node.data.time) / $scope.timelineIntervalDuration); + + if (startInterval === endInterval) { + + $scope.timeline[startInterval] += node.data.time; + + } else { + + var timeToDispatch = node.data.time; + + var startIntervalPart = ((startInterval + 1) * $scope.timelineIntervalDuration) - node.data.timestamp; + $scope.timeline[startInterval] += startIntervalPart; + timeToDispatch -= startIntervalPart; + + var currentInterval = startInterval; + while(currentInterval < endInterval && currentInterval + 1 < numberOfIntervals) { + currentInterval ++; + var currentIntervalPart = Math.min(timeToDispatch, $scope.timelineIntervalDuration); + $scope.timeline[currentInterval] = currentIntervalPart; + timeToDispatch -= currentIntervalPart; + } + } + } + + if (node.data.type !== 'main') { + // Don't check the children + return false; + } + }); + $scope.timelineMax = Math.max.apply(Math, $scope.timeline); } function initMetricsView() { diff --git a/app/public/styles/results.css b/app/public/styles/results.css index f666874..e26feec 100644 --- a/app/public/styles/results.css +++ b/app/public/styles/results.css @@ -115,6 +115,67 @@ h4 { background: #CCC; } +.timeline { + margin: 2em 0 5em; +} +.timeline .chart { + height: 100px; + width: 100%; + border-bottom: 1px solid #000; +} +.timeline .interval { + position: relative; + display: inline-block; + height: 100px; + width: 0.5%; +} +.timeline .interval > div { + position: absolute; + bottom: 0; + width: 100%; +} +.timeline .domCreation.interval { + background: #FFE0CC; +} +.timeline .domCreation .color { + background: #FF6600; +} +.timeline .domContentLoaded.interval { + background: #E0FFD1; +} +.timeline .domContentLoaded .color { + background: #99FF66; +} +.timeline .domContentLoadedEnd.interval { + background: #D8F0F0; +} +.timeline .domContentLoadedEnd .color { + background: #7ECCCC; +} +.timeline .domComplete.interval { + background: #EDE3FF; +} +.timeline .domComplete .color { + background: #C2A3FF; +} +.timeline .legend { + display: table; + width: 100%; +} +.timeline .legend > div { + display: table-cell; + margin-top: 1em; +} +.timeline .legend .color { + display: inline-block; + position: relative; + top: 0.4em; + height: 1.5em; + width: 1.5em; + border-radius: 0.5em; + margin: 0 0.2em 0 1em; +} + .metrics h4 { padding-left: 2em;