Как подсчитать общее количество часов на странице?
Есть ли способ в JavaScript подсчитать количество часов angular на всей странице?
Мы используем Batarang, но это не всегда соответствует нашим потребностям. Наше приложение является большим, и мы заинтересованы в использовании автоматических тестов, чтобы проверить, увеличивается ли количество часов.
Было бы также полезно считать часы на основе каждого контроллера.
Изменить: вот моя попытка. Он учитывает часы во всем с классом ng-scope.
(function () {
var elts = document.getElementsByClassName('ng-scope');
var watches = [];
var visited_ids = {};
for (var i=0; i < elts.length; i++) {
var scope = angular.element(elts[i]).scope();
if (scope.$id in visited_ids)
continue;
visited_ids[scope.$id] = true;
watches.push.apply(watches, scope.$$watchers);
}
return watches.length;
})();
Ответы
Ответ 1
(Вам может потребоваться изменить body
на html
или везде, где вы положили ng-app
)
(function () {
var root = angular.element(document.getElementsByTagName('body'));
var watchers = [];
var f = function (element) {
angular.forEach(['$scope', '$isolateScope'], function (scopeProperty) {
if (element.data() && element.data().hasOwnProperty(scopeProperty)) {
angular.forEach(element.data()[scopeProperty].$$watchers, function (watcher) {
watchers.push(watcher);
});
}
});
angular.forEach(element.children(), function (childElement) {
f(angular.element(childElement));
});
};
f(root);
// Remove duplicate watchers
var watchersWithoutDuplicates = [];
angular.forEach(watchers, function(item) {
if(watchersWithoutDuplicates.indexOf(item) < 0) {
watchersWithoutDuplicates.push(item);
}
});
console.log(watchersWithoutDuplicates.length);
})();
-
Благодаря erilem для указания этого ответа отсутствовал поиск $isolateScope
и наблюдатели, которые потенциально дублировались в его/ее ответе/комментарии.
-
Благодаря Ben2307, указав, что может потребоваться изменить 'body'
.
Оригинальные
Я сделал то же самое, кроме того, что я проверял атрибут data элемента HTML, а не его класс. Я побежал за вами:
http://fluid.ie/
И получил 83. Я побежал и получил 121.
(function () {
var root = $(document.getElementsByTagName('body'));
var watchers = [];
var f = function (element) {
if (element.data().hasOwnProperty('$scope')) {
angular.forEach(element.data().$scope.$$watchers, function (watcher) {
watchers.push(watcher);
});
}
angular.forEach(element.children(), function (childElement) {
f($(childElement));
});
};
f(root);
console.log(watchers.length);
})();
Я также помещаю это в свое:
for (var i = 0; i < watchers.length; i++) {
for (var j = 0; j < watchers.length; j++) {
if (i !== j && watchers[i] === watchers[j]) {
console.log('here');
}
}
}
И ничего не распечатано, поэтому я предполагаю, что мой лучше (тем, что он нашел больше часов), но мне не хватает интимных знаний angular, чтобы точно знать, что моя не является подходящим подмножеством набора решений.
Ответ 2
Я думаю, что упомянутые подходы являются неточными, поскольку они подсчитывают наблюдателей в одном и том же диапазоне. Вот моя версия букмарклета:
https://gist.github.com/DTFagus/3966db108a578f2eb00d
Он также показывает некоторые подробности для анализа наблюдателей.
Ответ 3
Вот хакерское решение, которое я собрал, основываясь на проверке структур области. Это "кажется" работает. Я не уверен, насколько это точно, и это определенно зависит от некоторых внутренних API. Я использую angularjs 1.0.5.
$rootScope.countWatchers = function () {
var q = [$rootScope], watchers = 0, scope;
while (q.length > 0) {
scope = q.pop();
if (scope.$$watchers) {
watchers += scope.$$watchers.length;
}
if (scope.$$childHead) {
q.push(scope.$$childHead);
}
if (scope.$$nextSibling) {
q.push(scope.$$nextSibling);
}
}
window.console.log(watchers);
};
Ответ 4
Существует новый chrome-плагин, который автоматически отображает текущие общие наблюдатели и последнее изменение (+/-) в любое время в вашем приложении... это чисто потрясающий.
https://chrome.google.com/webstore/detail/angular-watchers/nlmjblobloedpmkmmckeehnbfalnjnjk
Ответ 5
Как я недавно боролся с большим количеством наблюдателей в моем приложении, я обнаружил отличную библиотеку, называемую ng-stats - https://github.com/kentcdodds/ng-stats. Он имеет минимальную настройку и дает вам количество наблюдателей на текущей странице + продолжительность цикла дайджеста. Он также может проектировать небольшой график реального времени.
Ответ 6
Незначительное улучшение для Слова, подобные Джареду.
(function () {
var root = $(document.getElementsByTagName('body'));
var watchers = 0;
var f = function (element) {
if (element.data().hasOwnProperty('$scope')) {
watchers += (element.data().$scope.$$watchers || []).length;
}
angular.forEach(element.children(), function (childElement) {
f($(childElement));
});
};
f(root);
return watchers;
})();
Ответ 7
В AngularJS 1.3.2 к модулю ngMock был добавлен метод countWatchers
:
/**
* @ngdoc method
* @name $rootScope.Scope#$countWatchers
* @module ngMock
* @description
* Counts all the watchers of direct and indirect child scopes of the current scope.
*
* The watchers of the current scope are included in the count and so are all the watchers of
* isolate child scopes.
*
* @returns {number} Total number of watchers.
*/
function countWatchers()
{
var root = angular.element(document).injector().get('$rootScope');
var count = root.$$watchers ? root.$$watchers.length : 0; // include the current scope
var pendingChildHeads = [root.$$childHead];
var currentScope;
while (pendingChildHeads.length)
{
currentScope = pendingChildHeads.shift();
while (currentScope)
{
count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
pendingChildHeads.push(currentScope.$$childHead);
currentScope = currentScope.$$nextSibling;
}
}
return count;
}
Ссылки
Ответ 8
Я взял код ниже непосредственно из функции $digest
. Конечно, вам, вероятно, нужно обновить селектор элемента приложения (document.body
) внизу.
(function ($rootScope) {
var watchers, length, target, next, count = 0;
var current = target = $rootScope;
do {
if ((watchers = current.$$watchers)) {
count += watchers.length;
}
if (!(next = (current.$$childHead ||
(current !== target && current.$$nextSibling)))) {
while (current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
} while ((current = next));
return count;
})(angular.element(document.body).injector().get('$rootScope'));
Ответ 9
Это функции, которые я использую:
/**
* @fileoverview This script provides a window.countWatchers function that
* the number of Angular watchers in the page.
*
* You can do `countWatchers()` in a console to know the current number of
* watchers.
*
* To display the number of watchers every 5 seconds in the console:
*
* setInterval(function(){console.log(countWatchers())}, 5000);
*/
(function () {
var root = angular.element(document.getElementsByTagName('body'));
var countWatchers_ = function(element, scopes, count) {
var scope;
scope = element.data().$scope;
if (scope && !(scope.$id in scopes)) {
scopes[scope.$id] = true;
if (scope.$$watchers) {
count += scope.$$watchers.length;
}
}
scope = element.data().$isolateScope;
if (scope && !(scope.$id in scopes)) {
scopes[scope.$id] = true;
if (scope.$$watchers) {
count += scope.$$watchers.length;
}
}
angular.forEach(element.children(), function (child) {
count = countWatchers_(angular.element(child), scopes, count);
});
return count;
};
window.countWatchers = function() {
return countWatchers_(root, {}, 0);
};
})();
Эта функция использует хэш не для подсчета одной и той же области действия несколько раз.
Ответ 10
Существует рекурсивная функция, опубликованная блогом Ларса Эйдна в http://larseidnes.com/2014/11/05/angularjs-the-bad-parts/, чтобы собрать общее число наблюдателей. Я сравниваю результат, используя функцию, опубликованную здесь, и ту, которую он опубликовал в своем блоге, который породил несколько большее число. Я не могу сказать, какой из них более точным. Просто добавлен здесь как ссылка.
function getScopes(root) {
var scopes = [];
function traverse(scope) {
scopes.push(scope);
if (scope.$$nextSibling)
traverse(scope.$$nextSibling);
if (scope.$$childHead)
traverse(scope.$$childHead);
}
traverse(root);
return scopes;
}
var rootScope = angular.element(document.querySelectorAll("[ng-app]")).scope();
var scopes = getScopes(rootScope);
var watcherLists = scopes.map(function(s) { return s.$$watchers; });
_.uniq(_.flatten(watcherLists)).length;
ПРИМЕЧАНИЕ. Возможно, вам понадобится изменить "ng-app" на "data-ng-app" для вашего приложения Angular.
Ответ 11
Ответ по Plantian быстрее: fooobar.com/info/45027/...
Вот функция, которую я написал вручную. Я не думал об использовании рекурсивных функций, но именно это я и сделал. Это может быть более скудно, я не знаю.
var logScope; //put this somewhere in a global piece of code
Затем поместите это в свой самый высокий контроллер (если вы используете глобальный контроллер).
$scope.$on('logScope', function () {
var target = $scope.$parent, current = target, next;
var count = 0;
var count1 = 0;
var checks = {};
while(count1 < 10000){ //to prevent infinite loops, just in case
count1++;
if(current.$$watchers)
count += current.$$watchers.length;
//This if...else is also to prevent infinite loops.
//The while loop could be set to true.
if(!checks[current.$id]) checks[current.$id] = true;
else { console.error('bad', current.$id, current); break; }
if(current.$$childHead)
current = current.$$childHead;
else if(current.$$nextSibling)
current = current.$$nextSibling;
else if(current.$parent) {
while(!current.$$nextSibling && current.$parent) current = current.$parent;
if(current.$$nextSibling) current = current.$$nextSibling;
else break;
} else break;
}
//sort of by accident, count1 contains the number of scopes.
console.log('watchers', count, count1);
console.log('globalCtrl', $scope);
});
logScope = function () {
$scope.$broadcast('logScope');
};
И, наконец, закладки:
javascript:logScope();