Skip to content

Commit 2a62cd0

Browse files
committed
feat: add WTF tracing
- $digest - $digest#asyncQueue - $digest#postDigestQueue - $eval - $watcher - $compile#compile - $compile#link - $timeout Show events (ng-click, etc.) expressions. Show watched expressions. Show $timeout callbacks. Show reslving/rejecting promises details.
1 parent 550ba01 commit 2a62cd0

File tree

7 files changed

+164
-1
lines changed

7 files changed

+164
-1
lines changed

src/Angular.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
* <div doc-module-components="ng"></div>
104104
*/
105105

106+
var WTF_ENABLED = WTF && WTF.PRESENT;
107+
106108
var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
107109

108110
// The name of a form control's ValidityState property.

src/ng/compile.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,12 +1024,23 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10241024
*/
10251025
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
10261026
previousCompileContext) {
1027+
var wtfScope, wtfHtml;
1028+
1029+
if (WTF_ENABLED) {
1030+
wtfScope = WTF.trace.enterScope('$compile#compile');
1031+
wtfHtml = '';
1032+
}
1033+
10271034
var linkFns = [],
10281035
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
10291036

10301037
for (var i = 0; i < nodeList.length; i++) {
10311038
attrs = new Attributes();
10321039

1040+
if (WTF_ENABLED) {
1041+
wtfHtml += (nodeList[i].outerHTML || '');
1042+
}
1043+
10331044
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
10341045
directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
10351046
ignoreDirective);
@@ -1062,12 +1073,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10621073
previousCompileContext = null;
10631074
}
10641075

1076+
if (WTF_ENABLED) {
1077+
WTF.trace.appendScopeData('html', wtfHtml);
1078+
WTF.trace.leaveScope(wtfScope);
1079+
}
1080+
10651081
// return a linking function if we have found anything, null otherwise
10661082
return linkFnFound ? compositeLinkFn : null;
10671083

10681084
function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
10691085
var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
10701086
var stableNodeList;
1087+
var wtfLinkScope;
10711088

10721089

10731090
if (nodeLinkFnFound) {
@@ -1090,6 +1107,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10901107
nodeLinkFn = linkFns[i++];
10911108
childLinkFn = linkFns[i++];
10921109

1110+
if (WTF_ENABLED) {
1111+
wtfLinkScope = WTF.trace.enterScope('$compile#link');
1112+
WTF.trace.appendScopeData('html', node.outerHTML || node.textContent);
1113+
}
1114+
10931115
if (nodeLinkFn) {
10941116
if (nodeLinkFn.scope) {
10951117
childScope = scope.$new();
@@ -1118,6 +1140,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
11181140
} else if (childLinkFn) {
11191141
childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
11201142
}
1143+
1144+
if (WTF_ENABLED) {
1145+
WTF.trace.leaveScope(wtfLinkScope);
1146+
}
11211147
}
11221148
}
11231149
}

src/ng/directive/ngEventDirs.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ forEach(
6262
var callback = function() {
6363
fn(scope, {$event:event});
6464
};
65+
66+
if (WTF_ENABLED) {
67+
callback.toString = function() {
68+
return 'ng-' + name + '="' + attr[directiveName] + '"';
69+
};
70+
}
71+
6572
if (forceAsyncEvents[eventName] && scope.$$phase) {
6673
scope.$evalAsync(callback);
6774
} else {

src/ng/parse.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,11 @@ function $ParseProvider() {
11171117
// initial value is defined (for bind-once)
11181118
return isDefined(value) ? result : value;
11191119
};
1120+
1121+
if (WTF_ENABLED) {
1122+
fn.exp = parsedExpression;
1123+
}
1124+
11201125
fn.$$watchDelegate = parsedExpression.$$watchDelegate;
11211126
return fn;
11221127
}

src/ng/q.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,28 @@ function qFactory(nextTick, exceptionHandler) {
325325
function scheduleProcessQueue(state) {
326326
if (state.processScheduled || !state.pending) return;
327327
state.processScheduled = true;
328-
nextTick(function() { processQueue(state); });
328+
329+
var fn = function() { processQueue(state); };
330+
331+
if (WTF_ENABLED) {
332+
var pending = state.pending;
333+
334+
fn.toString = function() {
335+
var callbacks = state.pending.map(function(p) {
336+
return p[state.status];
337+
}).filter(function(callback) {
338+
return !!callback;
339+
}).map(function(callback) {
340+
return callback.name || callback.toString();
341+
});
342+
343+
return (state.status === 1 ? 'resolving' : 'rejecting') + ' promise\n' +
344+
'callbacks (' + callbacks.length + '):\n' + callbacks.join('\n\n') + '\n\n' +
345+
'value: ' + toJson(state.value, true);
346+
};
347+
}
348+
349+
nextTick(fn);
329350
}
330351

331352
function Deferred() {

src/ng/rootScope.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,11 @@ function $RootScopeProvider(){
622622
}
623623
}
624624

625+
if (WTF_ENABLED) {
626+
$watchCollectionAction.exp = listener;
627+
changeDetector.exp = obj;
628+
}
629+
625630
return this.$watch(changeDetector, $watchCollectionAction);
626631
},
627632

@@ -687,6 +692,15 @@ function $RootScopeProvider(){
687692
watchLog = [],
688693
logIdx, logMsg, asyncTask;
689694

695+
var wtfDigestScope, wtfDigestCycleScope, wtfDigestCycleCount, wtfAsyncQueueScope,
696+
wtfAsyncQueueCount, wtfWatcherScope;
697+
698+
if (WTF_ENABLED) {
699+
wtfDigestScope = WTF.trace.enterScope('$digest');
700+
wtfDigestCycleCount = 0;
701+
wtfAsyncQueueCount = 0;
702+
}
703+
690704
beginPhase('$digest');
691705
// Check for changes to browser url that happened in sync before the call to $digest
692706
$browser.$$checkUrlChange();
@@ -704,8 +718,17 @@ function $RootScopeProvider(){
704718
dirty = false;
705719
current = target;
706720

721+
if (WTF_ENABLED) {
722+
wtfDigestCycleCount++;
723+
wtfDigestCycleScope = WTF.trace.enterScope('$digest#' + wtfDigestCycleCount);
724+
wtfAsyncQueueScope = WTF.trace.enterScope('$digest#asyncQueue');
725+
}
726+
707727
while(asyncQueue.length) {
708728
try {
729+
if (WTF_ENABLED) {
730+
wtfAsyncQueueCount++
731+
}
709732
asyncTask = asyncQueue.shift();
710733
asyncTask.scope.$eval(asyncTask.expression);
711734
} catch (e) {
@@ -714,6 +737,11 @@ function $RootScopeProvider(){
714737
lastDirtyWatch = null;
715738
}
716739

740+
if (WTF_ENABLED) {
741+
WTF.trace.appendScopeData('length', wtfAsyncQueueCount);
742+
WTF.trace.leaveScope(wtfAsyncQueueScope);
743+
}
744+
717745
traverseScopesLoop:
718746
do { // "traverse the scopes" loop
719747
if ((watchers = current.$$watchers)) {
@@ -733,7 +761,33 @@ function $RootScopeProvider(){
733761
dirty = true;
734762
lastDirtyWatch = watch;
735763
watch.last = watch.eq ? copy(value, null) : value;
764+
765+
if (WTF_ENABLED) {
766+
wtfWatcherScope = WTF.trace.enterScope('watcher');
767+
if (watch.exp) {
768+
// interpolation watch.exp.exp
769+
// parse watch.exp
770+
if (watch.exp.exp) {
771+
WTF.trace.appendScopeData('exp', watch.exp.exp.toString());
772+
} else if (Object.hasOwnProperty.call(watch.exp, 'toString')) {
773+
WTF.trace.appendScopeData('exp', watch.exp.toString());
774+
} else {
775+
WTF.trace.appendScopeData('exp', watch.exp.name || watch.exp.toString());
776+
}
777+
}
778+
779+
WTF.trace.appendScopeData('get', (watch.get.name || watch.get.toString()));
780+
WTF.trace.appendScopeData('fn', (watch.fn.name || watch.fn.toString()));
781+
WTF.trace.appendScopeData('previous', toJson(last));
782+
WTF.trace.appendScopeData('current', toJson(value));
783+
}
784+
736785
watch.fn(value, ((last === initWatchVal) ? value : last), current);
786+
787+
if (WTF_ENABLED) {
788+
WTF.trace.leaveScope(wtfWatcherScope);
789+
}
790+
737791
if (ttl < 5) {
738792
logIdx = 4 - ttl;
739793
if (!watchLog[logIdx]) watchLog[logIdx] = [];
@@ -777,17 +831,41 @@ function $RootScopeProvider(){
777831
TTL, toJson(watchLog));
778832
}
779833

834+
if (WTF_ENABLED) {
835+
WTF.trace.leaveScope(wtfDigestCycleScope);
836+
}
837+
780838
} while (dirty || asyncQueue.length);
781839

840+
if (WTF_ENABLED) {
841+
WTF.trace.appendScopeData('cycles', wtfDigestCycleCount);
842+
WTF.trace.leaveScope(wtfDigestScope);
843+
}
844+
782845
clearPhase();
783846

847+
var wtfPostDigestQueueScope, wtfPostDigestQueueCount;
848+
849+
if (WTF_ENABLED) {
850+
wtfPostDigestQueueScope = WTF.trace.enterScope('$digest#postDigestQueue');
851+
wtfPostDigestQueueCount = 0;
852+
}
853+
784854
while(postDigestQueue.length) {
785855
try {
856+
if (WTF_ENABLED) {
857+
wtfPostDigestQueueCount++;
858+
}
786859
postDigestQueue.shift()();
787860
} catch (e) {
788861
$exceptionHandler(e);
789862
}
790863
}
864+
865+
if (WTF_ENABLED) {
866+
WTF.trace.appendScopeData('length', wtfPostDigestQueueCount);
867+
WTF.trace.leaveScope(wtfPostDigestQueueScope);
868+
}
791869
},
792870

793871

@@ -895,6 +973,20 @@ function $RootScopeProvider(){
895973
* @returns {*} The result of evaluating the expression.
896974
*/
897975
$eval: function(expr, locals) {
976+
if (WTF_ENABLED) {
977+
var wtfScope = WTF.trace.enterScope('$eval');
978+
979+
if (expr) {
980+
WTF.trace.appendScopeData('expression', Object.hasOwnProperty.call(expr, 'toString') ? expr.toString() : (expr.name || expr.toString()));
981+
}
982+
983+
var result = $parse(expr)(this, locals);
984+
985+
WTF.trace.leaveScope(wtfScope);
986+
987+
return result;
988+
}
989+
898990
return $parse(expr)(this, locals);
899991
},
900992

src/ng/timeout.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ function $TimeoutProvider() {
3939
timeoutId;
4040

4141
timeoutId = $browser.defer(function() {
42+
var wtfScope;
43+
44+
if (WTF_ENABLED) {
45+
wtfScope = WTF.trace.enterScope('$timeout');
46+
WTF.trace.appendScopeData('fn', fn.name || fn.toString());
47+
}
48+
4249
try {
4350
deferred.resolve(fn());
4451
} catch(e) {
@@ -50,6 +57,9 @@ function $TimeoutProvider() {
5057
}
5158

5259
if (!skipApply) $rootScope.$apply();
60+
if (WTF_ENABLED) {
61+
WTF.trace.leaveScope(wtfScope);
62+
}
5363
}, delay);
5464

5565
promise.$$timeoutId = timeoutId;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy