web-dev-qa-db-fra.com

Comment obtenir des appels de fonction Javascript / trace au moment de l'exécution

Comme j'interagis avec mon AJAX à RUNTIME j'aimerais que la console recrache toutes les fonctions qu'elle appelle (donc pas de trace de pile, ni de points d'arrêt, ni de profilage ou quoi que ce soit)

Par exemple, disons que j'ai appuyé sur un bouton de la page. J'aimerais qu'il retourne toutes les fonctions qu'il a traversées quand cela s'est produit:

Je verrais donc dans la console quelque chose comme (lorsque j'appuyais sur un bouton):

1. button1Clicked();
2.     calculating();
3.          printingResults();

Ce qui signifie essentiellement que button1Clicked () a appelé calculating () qui a appelé printingResults ()

Existe-t-il un utilitaire, un plugin, un navigateur ou peut-être un moyen dans la langue de le faire? J'utilise Google Chrome, BTW.

p.s et NON Je ne veux pas passer par chaque fonction et ajouter une "console.log("inside function X")" b/c c'est trop de travail

p.p.s comme un bonus supplémentaire, je voudrais voir les arguments passés dans les fonctions aussi, mais c'est peut-être le pousser. :>

35
foreyez

Je ne peux pas penser à un excellent moyen d'intercepter tous les appels de fonction à l'échelle mondiale pour insérer la journalisation (bien qu'il existe une solution de contournement décente dans la section de mise à jour ci-dessous).

Au lieu de cela, que diriez-vous d'ajouter uniquement la journalisation aux fonctions dans un certain espace de noms qui vous tient à cœur? Vous pouvez le faire avec le code d'installation suivant:

var functionLogger = {};

functionLogger.log = true;//Set this to false to disable logging 

/**
 * Gets a function that when called will log information about itself if logging is turned on.
 *
 * @param func The function to add logging to.
 * @param name The name of the function.
 *
 * @return A function that will perform logging and then call the function. 
 */
functionLogger.getLoggableFunction = function(func, name) {
    return function() {
        if (functionLogger.log) {
            var logText = name + '(';

            for (var i = 0; i < arguments.length; i++) {
                if (i > 0) {
                    logText += ', ';
                }
                logText += arguments[i];
            }
            logText += ');';

            console.log(logText);
        }

        return func.apply(this, arguments);
    }
};

/**
 * After this is called, all direct children of the provided namespace object that are 
 * functions will log their name as well as the values of the parameters passed in.
 *
 * @param namespaceObject The object whose child functions you'd like to add logging to.
 */
functionLogger.addLoggingToNamespace = function(namespaceObject){
    for(var name in namespaceObject){
        var potentialFunction = namespaceObject[name];

        if(Object.prototype.toString.call(potentialFunction) === '[object Function]'){
            namespaceObject[name] = functionLogger.getLoggableFunction(potentialFunction, name);
        }
    }
};

Ensuite, pour tout objet namespaceObject auquel vous souhaitez ajouter la journalisation, vous appelez simplement:

functionLogger.addLoggingToNamespace(yourNamespaceObject);

Voici un violon pour le voir en action.

[~ # ~] mise à jour [~ # ~]
Notez que vous pouvez appeler functionLogger.addLoggingToNamespace(window); pour ajouter la journalisation à toutes les fonctions globales au moment de l'appel. De plus, si vous le voulez vraiment, vous pouvez parcourir l'arborescence pour trouver des fonctions et les mettre à jour en conséquence. Le seul inconvénient de cette méthode est qu'elle ne fonctionne que sur les fonctions qui existent à l'époque. Ainsi, ce n'est toujours pas la meilleure solution, mais c'est beaucoup moins de travail que d'ajouter des instructions de journalisation à la main :)

34
Briguy37

Cela s'appelle le profilage et Chrome et Firebug l'ont intégré. Dans Chrome Developer Tools , allez dans l'onglet Profils et cliquez sur le bouton d'enregistrement (cercle). Effectuez votre ajax et après votre réponse, cliquez à nouveau sur le bouton d'enregistrement pour arrêter. Les résultats du profilage apparaîtront dans le volet droit.

Remarque, cela va vous donner tout donc si vous utilisez une bibliothèque comme jQuery, la grande majorité des appels de fonction vont être des ordures pour vous. J'ai essayé cela plusieurs fois et je trouve qu'il est beaucoup plus utile de faire la chose console.log('inside <method>').

16
Jeff

Une variante de la solution de Briguy37, j'en ai écrit une qui accepte une fonction à appeler avant chaque méthode. Il fonctionne également avec les classes ECMAScript 6, où les méthodes ne sont pas énumérées par for ... in. Je l'utilise pour modifier les prototypes d'objets, pour ajouter la journalisation à toutes les nouvelles instances de mon objet.

function inject(obj, beforeFn) {
    for (let propName of Object.getOwnPropertyNames(obj)) {
        let prop = obj[propName];
        if (Object.prototype.toString.call(prop) === '[object Function]') {
            obj[propName] = (function(fnName) {
                return function() {
                    beforeFn.call(this, fnName, arguments);
                    return prop.apply(this, arguments);
                }
            })(propName);
        }
    }
}

function logFnCall(name, args) {
    let s = name + '(';
    for (let i = 0; i < args.length; i++) {
        if (i > 0)
            s += ', ';
        s += String(args[i]);
    }
    s += ')';
    console.log(s);
}

inject(Foo.prototype, logFnCall);
2
Peter Tseng

Essayez de diyism_trace_for_javascript.htm:

https://code.google.com/p/diyism-trace/downloads/list

eval('window.c=function(){3+5;}');
declare_ticks_for(window);

function a(k, c) {
  return k + 2;
}

function b() {
  4 + 3;
  a(3, {'a':'c','b':'d'});
  c();
  return 5 + 4;
}

b();

Afficher les journaux dans l'onglet console de chrome ou firefox

2
diyism

Vous pouvez peut-être demander à JavaScript de faire le travail d'ajout de console.log pour vous:

Ajout automatique de console.log à chaque fonction

Ce blog de Paul Irish pourrait également aider:

http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/

Il comprend un lien vers du JavaScript spécifiquement ciblé sur les arguments de journalisation:

http://pastie.org/1033665

2
Jason Sperske

J'ai utilisé la solution de @ Briguy37 avec une amélioration. Dans mon cas, je ne voulais pas tracer les fonctions de certaines bibliothèques, j'ai donc ajouté du code pour les exclure. Voici comment il est utilisé:

  • Commencez par inclure la définition des fonctions que vous ne souhaitez pas tracer;
  • excludeLoggingToNamespace pour lister les fonctions définies jusqu'à présent et les exclure;
  • Incluez la définition des fonctions que vous souhaitez tracer;
  • Appelez addLoggingToNamespace pour ajouter la fonction de journalisation aux fonctions définies à l'étape ci-dessus.

Exemple:

<script src="js/someLibrary.js"></script>
<script>
    functionLogger.excludeLoggingToNamespace(window);
</script>
<script src="js/codeIWantToTraceHere.js"></script>
<script>
    functionLogger.addLoggingToNamespace(window);
</script>

Voici le code que j'ai ajouté à la solution de @ Briguy37:

var excludedFunctions = {};

        functionLogger.excludeLoggingToNamespace = function(namespaceObject){
            for(var name in namespaceObject){
                var potentialFunction = namespaceObject[name];

                if(Object.prototype.toString.call(potentialFunction) === '[object Function]') {
                    excludedFunctions[name] = name;
                }
            }
        }; 

Et j'ai dû modifier la méthode addLoggingToNamespace de @ Briguy37 pour prendre en compte le hachage exclusFunctions:

functionLogger.addLoggingToNamespace = function(namespaceObject){
    for(var name in namespaceObject){
        var potentialFunction = namespaceObject[name];

        if(Object.prototype.toString.call(potentialFunction) === '[object Function]' && 
           !excludedFunctions[name]) {
            namespaceObject[name] = functionLogger.getLoggableFunction(potentialFunction, name);
        }
    }
};    
0