पृष्ठ पर घड़ियों की कुल संख्या की गणना कैसे करें?


144

पूरे पृष्ठ पर कोणीय घड़ियों की संख्या की गणना करने के लिए जावास्क्रिप्ट में एक रास्ता है?

हम बतरंग का उपयोग करते हैं , लेकिन यह हमेशा हमारी आवश्यकताओं के अनुरूप नहीं होता है। हमारा आवेदन बड़ा है और हम यह देखने के लिए स्वचालित परीक्षणों का उपयोग करने में रुचि रखते हैं कि क्या घड़ी की गिनती बहुत अधिक हो गई है।

प्रति-नियंत्रक आधार पर घड़ियों की गणना करना भी उपयोगी होगा।

संपादित करें : यहाँ मेरा प्रयास है। यह वर्ग एनजी-स्कोप के साथ हर चीज में घड़ियों को गिनता है।

(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;
})();

प्रति नियंत्रक आसान है। प्रत्येक के $scopeपास उस नियंत्रक पर देखने वालों की संख्या के साथ $ $ वॉचर सरणी होती है (ठीक है, अगर आपके पास कुछ एनजी-रिपीट या ऐसा कुछ है जो एक और गुंजाइश बनाता है, जो उस अच्छे काम नहीं करता है)। लेकिन मुझे लगता है कि पूरे ऐप में सभी घड़ियों को देखने का कोई तरीका नहीं है।
यीशु रोड्रिगेज

जवाबों:


220

(आपको अपने स्थान 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खोज को याद कर रहा था और देखने वालों को संभवतः उसके उत्तर / टिप्पणी में दोहराया जा रहा था।

  • यह इंगित करने के लिए कि 'body'परिवर्तन करने की आवश्यकता हो सकती है, इसके लिए Ben2307 का धन्यवाद ।


मूल

मैंने ऐसा ही किया, सिवाय इसके कि मैंने अपनी कक्षा के बजाय 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');
        }
    }
}

और कुछ भी नहीं छपा है, इसलिए मैं अनुमान लगा रहा हूं कि मेरा बेहतर है (इसमें अधिक घड़ियां मिलीं) - लेकिन मुझे यह जानने के लिए अंतरंग कोणीय ज्ञान की कमी है कि मेरा समाधान सेट का एक उचित सबसेट नहीं है।


2
मैं कुछ ऐसा ही करने की कोशिश कर रहा हूं, और इस स्निपेट को बहुत मदद मिली। एक बात जो मुझे लगता है कि मैं स्पष्ट करने के लायक है कि 'रूट' को 'एनजी-ऐप' विशेषता के किसी भी तत्व के लिए सेट किया जाना चाहिए, क्योंकि यही वह जगह है जहां $ रूटस्कॉप रखा गया है। मेरे ऐप में 'html' टैग पर। मेरे एप में $ rootScope में $ द्रष्टा के रूप में आपकी स्क्रिप्ट को चलाने से चूक गया।
आमिरी

मुझे उपरोक्त कोड में एक समस्या मिली: यदि किसी बाल तत्व का स्वयं का दायरा है, लेकिन अब वॉचर्स, $ स्कोप नहीं होगा। $$ वॉचर्स इसे पेरेंट स्कोप के वॉचर्स को लौटाते हैं? मुझे लगता है कि आपको इस तरह से धक्का देने से पहले जोड़ना चाहिए (मैं लॉश का उपयोग कर रहा हूं): अगर (! (शामिल होते हैं, वॉचर)) {वॉचर्स.पश (वॉचर); }
बेन

2
यह उन सभी वॉचरों को प्राप्त होता है जो DOM तत्वों से जुड़े होते हैं। यदि आप एक DOM तत्व निकालते हैं, तो क्या संबंधित $scopeऔर $$watcherस्वचालित की सफाई है , या क्या कोई प्रदर्शन हिट है जो वे प्रभावित करते हैं?
सिंपलजी

क्या यह नए वन-टाइम बाइंडिंग फीचर को ध्यान में रखता है? क्या आपकी गिनती इस तरह के बंधन को छोड़ती है?
systempuntoout

10
बस एक सिर ऊपर: यदि आप $compileProvider.debugInfoEnabled(false);अपने प्रोजेक्ट में उपयोग करते हैं, तो यह स्निपेट शून्य पर नजर रखने वालों की गिनती करेगा।
माइकल क्लोपीज

16

मुझे लगता है कि उल्लिखित दृष्टिकोण गलत हैं क्योंकि वे एक ही दायरे के दोहरे में पहरेदारों की गिनती करते हैं। यहाँ एक बुकमार्कलेट का मेरा संस्करण है:

https://gist.github.com/DTFagus/3966db108a578f2eb00d

यह देखने वालों के विश्लेषण के लिए कुछ और विवरण भी दिखाता है।


12

यहाँ एक घिनौना समाधान है जो मैंने गुंजाइश संरचनाओं के निरीक्षण के आधार पर एक साथ रखा है। यह काम करने के लिए "लगता है"। मुझे यकीन नहीं है कि यह कितना सही है और यह निश्चित रूप से कुछ आंतरिक एपीआई पर निर्भर करता है। मैं 1.0.5 angularjs का उपयोग कर रहा हूं।

    $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);
    };

यह मेरे मूल समाधान के समान है (इतिहास संपादित करें देखें)। मैं एक अलग दृष्टिकोण पर चला गया क्योंकि मुझे लगता है कि गुंजाइश चलना पदानुक्रम अलग-थलग स्कोप को याद करेगा।
ty।

3
अगर मैं नियंत्रक के लिए एक अलग गुंजाइश बनाता हूं $rootScope.$new(true)या $scope.$new(true)कहां $scopeहै, तो पदानुक्रम चलना अभी भी उस दायरे को पाता है। मुझे लगता है कि इसका मतलब यह है कि इसके बजाय प्रोटोटाइप जुड़े नहीं हैं, गुंजाइश पदानुक्रम में नहीं है।
इयान विल्सन

हां, सभी स्कोप $ रूटस्कोप से उतरते हैं, केवल पृथक स्कोप में विरासत "पृथक" है। पृथक स्कोप अक्सर निर्देशों में उपयोग किए जाते हैं - यहां आप माता-पिता से हस्तक्षेप के लिए ऐप-चर नहीं चाहते हैं।
markmarijnissen

यदि आप अपने द्वारा बनाए गए स्कोप का पता लगाने की कोशिश कर रहे हैं, लेकिन सफाई नहीं करते हैं, तो यह तरीका बेहतर है। मेरे मामले में, DOM को क्रॉल करना हमेशा समान संख्या में स्कोप दिखाता है लेकिन जो DOM-संलग्न नहीं हैं वे शैडोलैंड में गुणा कर रहे हैं।
सिंपलजी

10

एक नया क्रोम प्लगइन है जो स्वचालित रूप से आपके ऐप में किसी भी समय वर्तमान कुल वॉचर्स और अंतिम परिवर्तन (+/-) दिखाता है ... यह शुद्ध भयानक है।

https://chrome.google.com/webstore/detail/angular-watchers/nlmjblobloedpmkmmckeehnbfalnjnjk


यह वास्तव में बहुत उपयुक्त है
सुजीत वाई। कुलकर्णी

9

जैसा कि मैं हाल ही में अपने आवेदन में अधिक संख्या में देखने वालों के साथ संघर्ष कर रहा था, मुझे भी एक महान पुस्तकालय का पता चला, जिसे एनजी-आँकड़े कहा जाता है - https://github.com/kentcdodds/ng-stats । यह कम से कम सेटअप है और आप वर्तमान पृष्ठ पर नजर रखने वालों की संख्या देता है + चक्र डाइजेस्ट लंबाई। यह भी एक छोटे से वास्तविक समय ग्राफ परियोजना सकता है।


8

जारेड के जवाब जैसे शब्दों के लिए मामूली सुधार ।

(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;
})();

2
क्योंकि आप jQuery चयनकर्ताओं का उपयोग नहीं कर रहे हैं, आप $ के बजाय angular.element () का उपयोग कर सकते हैं ()
दाढ़ी वाले

8

AngularJS 1.3.2 में, एक countWatchersविधि ngMock मॉड्यूल में जोड़ा गया था:

/ **
 * @ngdoc विधि
 * @name $ rootScope.Scope # $ countWatchers
 * @ मडूले ngMock
 * @विवरण
 * वर्तमान दायरे के प्रत्यक्ष और अप्रत्यक्ष बाल scopes के सभी दर्शकों को गिना जाता है।
 *
 * करंट स्कोप के वॉचर्स को काउंट में शामिल किया गया है और इसलिए सभी वॉचर्स इसके हैं
 * अलग बच्चे scopes।
 *
 * @Returns {संख्या} पर नजर रखने वालों की कुल संख्या।
 * /

  फ़ंक्शन काउंटवॉचर्स () 
   {
   var root = angular.element (document) .injector ()। get ('$ rootScope');
   var count = root। $ $ वॉचर्स? जड़। $ $ पहरेदार। // वर्तमान गुंजाइश शामिल करें
   var लंबित चिल्डहेड्स = [रूट। $ $ चाइल्डहेड];
   var currentScope;

   जबकि (लंबित हैल्डहेड्स 
    {
    currentScope = लंबितChildHeads.shift ();

    जबकि (करंट स्कोप) 
      {
      गिनती + = currentScope। $$ पहरेदार? currentScope। $$ पहरेदार।
      pendingChildHeads.push (currentScope $$ childHead।);
      currentScope = currentScope। $$ nextSibling;
      }
    }

   वापसी की गिनती;
   }

संदर्भ


1
धन्यवाद! मैं बदल angular.element(document)करने के लिए angular.element('[ng-app]')और एक चेतावनी के साथ एक बुकमार्कलेट में रख:alert('found ' + countWatchers() + ' watchers');
अपरिभाषित

4

मैंने $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'));


1

यह मेरे द्वारा उपयोग किए जाने वाले कार्य हैं:

/**
 * @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);
  };

})();

इस समारोह में एक ही दायरे में कई बार गिनती करने के लिए नहीं एक हैश का उपयोग करता है।


मुझे लगता है कि element.data()कभी-कभी अपरिभाषित या कुछ भी हो सकता है (कम से कम 1.0.5 आवेदन पर कि मुझे एक त्रुटि मिली जब मैंने इस स्निप को चलाया और कॉल करने की कोशिश की countWatchers)। सिर्फ आपकी जानकारी के लिए।
जारेड

1

कुल संख्या पर नजर रखने वालों को इकट्ठा करने के लिए लार्स ईडनेस के ब्लॉग 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;

ध्यान दें: आपको अपने Angular ऐप के लिए "ng-app" को "data-ng-app" में बदलने की आवश्यकता हो सकती है।


1

प्लांटियन का जवाब तेज है: https://stackoverflow.com/a/18539624/258482

यहाँ एक फंक्शन है जिसे मैंने लिखा है। मैंने पुनरावर्ती कार्यों का उपयोग करने के बारे में नहीं सोचा था, लेकिन यह वही है जो मैंने इसके बजाय किया। यह दुबला हो सकता है, मुझे नहीं पता।

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();

0

इस प्रश्न के लिए थोड़ी देर हो गई, लेकिन मैं इसका उपयोग करता हूं

angular.element(document.querySelector('[data-ng-app]')).scope().$$watchersCount

बस सुनिश्चित करें कि आप सही क्वेरी का उपयोग करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.