Skip to content

Commit 52cb692

Browse files
author
Nicolas Joseph
committed
Merge branch 'develop' for release 0.0.2
2 parents 247ea4c + e7a1dad commit 52cb692

File tree

10 files changed

+204
-55
lines changed

10 files changed

+204
-55
lines changed

.scss/app.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,16 @@
1212

1313
#digest-time-distribution-range-slider{
1414
margin-top: 20px;
15+
}
16+
17+
.rickshaw_annotation_timeline .annotation.active .content {
18+
display: inline-block;
19+
}
20+
21+
.rickshaw_annotation_timeline .annotation:hover .content{
22+
display: inline-block;
23+
}
24+
25+
.rickshaw_annotation_timeline .annotation .content {
26+
width: auto;
1527
}

extension/css/app.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,18 @@
1717
#digest-time-distribution-range-slider {
1818
margin-top: 20px;
1919
}
20+
21+
/* line 17, ../../.scss/app.scss */
22+
.rickshaw_annotation_timeline .annotation.active .content {
23+
display: inline-block;
24+
}
25+
26+
/* line 21, ../../.scss/app.scss */
27+
.rickshaw_annotation_timeline .annotation:hover .content {
28+
display: inline-block;
29+
}
30+
31+
/* line 25, ../../.scss/app.scss */
32+
.rickshaw_annotation_timeline .annotation .content {
33+
width: auto;
34+
}

extension/src/background.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ chrome.runtime.onConnect.addListener(function(port){
6262
}
6363

6464
if (sender.tab) {
65+
6566
var tabId = sender.tab.id;
6667

6768
if (!contentScriptConnections[tabId]){
@@ -73,7 +74,7 @@ chrome.runtime.onConnect.addListener(function(port){
7374
} else if (tabId in panelConnections) {
7475
panelConnections[tabId].postMessage(message);
7576
} else {
76-
console.log('background.js - Tab not found in connection list.');
77+
console.log('background.js - Tab not found in connection list.', sender.tab.id, panelConnections);
7778
}
7879
} else {
7980
console.log('background.js - sender.tab not defined.');
@@ -93,7 +94,6 @@ chrome.runtime.onConnect.addListener(function(port){
9394
panelConnections[message.tabId] = port
9495

9596
} else if (message.task === 'sendTaskToInspector') {
96-
9797
contentScriptConnections[message.tabId].postMessage(message.data)
9898

9999
} else if (message.task === 'log'){
@@ -136,6 +136,14 @@ chrome.runtime.onConnect.addListener(function(port){
136136

137137
port.onDisconnect.addListener(function(){
138138
port.onMessage.removeListener(contentScriptListener);
139+
140+
var tabs = Object.keys(contentScriptConnections);
141+
for (var i=0, len=tabs.length; i < len; i++) {
142+
if (contentScriptConnections[tabs[i]] == port) {
143+
delete contentScriptConnections[tabs[i]];
144+
break;
145+
}
146+
}
139147
});
140148

141149

@@ -148,12 +156,27 @@ chrome.runtime.onConnect.addListener(function(port){
148156
port.onMessage.removeListener(panelListener);
149157

150158
var tabs = Object.keys(panelConnections);
151-
for (var i=0, len=tabs.length; i < len; i++) {
159+
for (var i = 0, len = tabs.length; i < len ; i++) {
152160
if (panelConnections[tabs[i]] == port) {
153161
delete panelConnections[tabs[i]];
162+
// On panel closing, clean up the tab from all wrapped functions and removes the injector.js
163+
contentScriptConnections[tabs[i]].postMessage({
164+
task: 'cleanUpInspectedApp',
165+
source: 'angular-performance'
166+
});
154167
break;
155168
}
156169
}
157170
});
158171
}
159172
});
173+
174+
// We want to inject the content-script again if the page is refreshed
175+
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo){
176+
// The page has to be completely loaded before we inject the content script inside.
177+
if (changeInfo.status === 'complete' && panelConnections[tabId]) {
178+
chrome.tabs.executeScript(tabId, {
179+
file: 'src/injected/content-script.js'
180+
});
181+
}
182+
});

extension/src/injected/content-script.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ window.addEventListener('message', function(event) {
105105
return;
106106
}
107107

108+
if (message.task === 'removeInspector'){
109+
// removes the inspector from the DOM
110+
var inspector = document.getElementById("angular-performance-inspector");
111+
inspector.parentNode.removeChild(inspector);
112+
return;
113+
}
114+
108115
backgroundPageConnection.postMessage(message);
109116
}, false);
110117

@@ -129,6 +136,7 @@ USER_EVENTS.forEach(function(eventType){
129136
// Add injected script to the page
130137
var script = document.createElement('script');
131138
script.type = 'text/javascript';
139+
script.id = 'angular-performance-inspector';
132140
script.src = chrome.extension.getURL('src/injected/inspector.js');
133141
document.head.appendChild(script);
134142

extension/src/injected/inspector.js

Lines changed: 122 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
'use strict';
1414

1515
var
16-
_angularInjector;
16+
_angularInjector,
17+
_isMonitoringActive = true,
18+
_backUp = {
19+
digest: null,
20+
modules: {}
21+
};
1722

1823
console.log('angular-performance - Inspector loaded into webpage');
1924

@@ -36,6 +41,40 @@
3641
source: 'angular-performance-inspector'
3742
}, '*');
3843

44+
// We listen for async instrumentation instructions
45+
window.addEventListener('message', function(event){
46+
// We only accept messages from ourselves
47+
if (event.source != window || event.data.source !== 'angular-performance') {
48+
return;
49+
}
50+
51+
var message = event.data;
52+
53+
switch (message.task){
54+
55+
case 'checkModuleName':
56+
var moduleServices = getNgModuleServices(message.moduleName);
57+
// If there is no services the method will return an empty object, if the module name is
58+
// invalid, it will return undefined.
59+
sendTask('reportModuleExistence', {
60+
moduleName: message.moduleName,
61+
services: (moduleServices) ? Object.keys(moduleServices) : undefined
62+
});
63+
break;
64+
65+
case 'instrumentModuleServices':
66+
instrumentModuleServices(message.moduleName);
67+
break;
68+
69+
case 'cleanUpInspectedApp':
70+
_isMonitoringActive = false;
71+
cleanUpInspectedApp();
72+
// Once everything is cleaned up, we can remove this script from the DOM
73+
sendTask('removeInspector');
74+
break;
75+
}
76+
});
77+
3978
bootstrapInspector();
4079
}
4180
}
@@ -49,48 +88,53 @@
4988

5089
_angularInjector = angular.element(document.querySelector('[ng-app]')).injector().get;
5190

52-
var $rootScope = getRootScope();
53-
var scopePrototype = Object.getPrototypeOf($rootScope);
54-
var oldDigest = scopePrototype.$digest;
91+
instrumentDigest();
92+
initWatcherCount();
93+
}
94+
95+
/**
96+
* This should clean up all that has been instrumented by the inspector and get them back
97+
* to their normal behaviour. (UnWrap everything)
98+
*/
99+
function cleanUpInspectedApp(){
100+
restoreDigest();
101+
restoreModuleServices();
102+
}
103+
104+
// ------------------------------------------------------------------------------------------
105+
// Digest Monitoring
106+
// ------------------------------------------------------------------------------------------
107+
108+
/**
109+
* Wraps the angular digest so that we can measure how long it take for the digest to happen.
110+
*/
111+
function instrumentDigest(){
112+
113+
var scopePrototype = Object.getPrototypeOf(getRootScope());
114+
_backUp.digest = scopePrototype.$digest;
55115

56116
scopePrototype.$digest = function $digest() {
57117
var start = performance.now();
58-
oldDigest.apply(this, arguments);
118+
_backUp.digest.apply(this, arguments);
59119
var time = (performance.now() - start);
60120
register('DigestTiming', {
61121
timestamp: Date.now(),
62122
time: time
63123
});
64124
};
125+
}
65126

66-
// We listen for async instrumentation instructions
67-
window.addEventListener('message', function(event){
68-
// We only accept messages from ourselves
69-
if (event.source != window || event.data.source !== 'angular-performance') {
70-
return;
71-
}
72-
73-
var message = event.data;
74-
75-
if (message.task === 'checkModuleName'){
76-
77-
var moduleServices = getNgModuleServices(message.moduleName);
78-
79-
// If there is no services the method will return an empty object, if the module name is
80-
// invalid, it will return undefined.
81-
82-
sendTask('reportModuleExistence', {
83-
moduleName: message.moduleName,
84-
services: (moduleServices) ? Object.keys(moduleServices) : undefined
85-
});
86-
} else if (message.task === 'instrumentModuleServices'){
87-
instrumentModuleServices(message.moduleName);
88-
}
89-
});
90-
91-
initWatcherCount();
127+
/**
128+
* Restores the classic angular digest.
129+
*/
130+
function restoreDigest(){
131+
Object.getPrototypeOf(getRootScope()).$digest = _backUp.digest;
92132
}
93133

134+
// ------------------------------------------------------------------------------------------
135+
// Scope & Watcher Exploration
136+
// ------------------------------------------------------------------------------------------
137+
94138
/**
95139
* Function to be called once to init the watcher retrieval.
96140
*/
@@ -102,14 +146,11 @@
102146
location: window.location.href
103147
}
104148
});
105-
setTimeout(initWatcherCount, 300);
149+
if (_isMonitoringActive) {
150+
setTimeout(initWatcherCount, 300);
151+
}
106152
}
107153

108-
// ------------------------------------------------------------------------------------------
109-
// Scope & Watcher Exploration
110-
// ------------------------------------------------------------------------------------------
111-
112-
113154
/**
114155
* Retrieves the watcher count for a particular scope
115156
*
@@ -279,8 +320,10 @@
279320
services = {};
280321
}
281322

323+
var module;
324+
282325
try {
283-
var module = angular.module(moduleName);
326+
module = angular.module(moduleName);
284327
} catch(e){
285328
return;
286329
}
@@ -305,10 +348,12 @@
305348
*/
306349
function instrumentModuleServices(moduleName){
307350

351+
_backUp.modules[moduleName] = {};
308352
var services = getNgModuleServices(moduleName);
309353

310354
angular.forEach(Object.keys(services), function(serviceName){
311355

356+
_backUp.modules[moduleName][serviceName] = {};
312357
var service = services[serviceName];
313358

314359
angular.forEach(Object.getOwnPropertyNames(service), function(propertyName){
@@ -323,7 +368,7 @@
323368
return;
324369
}
325370

326-
var functionToWrap = service[propertyName];
371+
var functionToWrap = _backUp.modules[moduleName][serviceName][propertyName] = service[propertyName];
327372

328373
// We Wrap all the service functions to measure execution time.
329374
service[propertyName] = function(){
@@ -363,6 +408,43 @@
363408
console.log('Module: ' + moduleName + ' successfully instrumented');
364409
}
365410

411+
/**
412+
* Restores the services functions as they were before being wrapped
413+
*
414+
* @param {String} [moduleName] - name of the module to be unwrapped. If not mentioned, everything
415+
* should be restored.
416+
*/
417+
function restoreModuleServices(moduleName){
418+
419+
var modules;
420+
421+
if (moduleName){
422+
423+
if (_backUp.modules[moduleName]) {
424+
modules = [moduleName];
425+
} else {
426+
throw new Error('angular performance - We tried to restore the module '+ moduleName + 'but ' +
427+
'we could not find any back up :(');
428+
}
429+
430+
} else {
431+
modules = Object.keys(_backUp.modules);
432+
}
433+
434+
angular.forEach(modules, function(module){
435+
var services = getNgModuleServices(module);
436+
437+
angular.forEach(Object.keys(_backUp.modules[module]), function(service){
438+
angular.forEach(Object.keys(_backUp.modules[module][service]), function(fnName){
439+
services[service][fnName] = _backUp.modules[module][service][fnName]
440+
});
441+
});
442+
443+
// Clean up back up
444+
delete _backUp.modules[module];
445+
});
446+
}
447+
366448
// ------------------------------------------------------------------------------------------
367449
// Utils
368450
// ------------------------------------------------------------------------------------------
@@ -371,7 +453,7 @@
371453
* Reports a metric
372454
*
373455
* @param {String} task - task to do
374-
* @param {Object} value - data that can be sent along with the task
456+
* @param {Object} [value] - data that can be sent along with the task
375457
*/
376458
function sendTask(task, value){
377459
window.postMessage({

0 commit comments

Comments
 (0)