如何在运行时获取 Javascript 函数调用/跟踪

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11853256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 07:23:54  来源:igfitidea点击:

How to get Javascript Function Calls/Trace at Runtime

javascriptfunctiongoogle-chromeruntimetrace

提问by foreyez

As I interact with my AJAX based application at RUNTIMEI'd like the console to spit out all the functions it's calling. (so no stack trace, or breakpoints, or profiling or anything)

当我在RUNTIME与基于 AJAX 的应用程序交互时,我希望控制台吐出它正在调用的所有函数。(所以没有堆栈跟踪,或断点,或分析或任何东西)

So for example, let's say I pressed a button on the page. I'd like for it to return all the functions it went through when that happened:

例如,假设我按下了页面上的一个按钮。我希望它返回发生这种情况时经历的所有功能:

So I'd see in the console something like (when I pressed a button):

所以我会在控制台中看到类似的东西(当我按下按钮时):

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

Which basically means that button1Clicked() called calculating() which called printingResults()

这基本上意味着 button1Clicked() 调用了calculation() 调用了printingResults()

Is there a utility, or plugin, browser, or maybe some way in the language to do this? I'm using google chrome, btw.

是否有实用程序、插件、浏览器或语言中的某种方式来执行此操作?我正在使用谷歌浏览器,顺便说一句。

p.s and NO I do not want to go through each function and add a "console.log("inside function X")"b/c that's too much work

ps 和 NO 我不想遍历每个函数并添加一个"console.log("inside function X")"工作量太大的b/c

p.p.s as an added bonus I'd like to see the arguments passed into the functions too, but maybe that's pushing it. :>

pps 作为一个额外的好处我也希望看到传递给函数的参数,但也许这正在推动它。:>

采纳答案by Briguy37

I can't think of a great way to intercept all function calls globally to insert logging (though there is a decent workaround in the update section below).

我想不出一个很好的方法来拦截全局所有函数调用以插入日志(尽管下面的更新部分有一个不错的解决方法)。

Instead, how about only adding logging to functions in a certain namespace that you care about? You can do this with the following setup code:

相反,仅向您关心的某个命名空间中的函数添加日志记录如何?您可以使用以下设置代码执行此操作:

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

Then, for whatever namespaceObject you want to add logging to, you just call:

然后,对于您想要添加日志记录的任何 namespaceObject,您只需调用:

functionLogger.addLoggingToNamespace(yourNamespaceObject);

Here's a fiddleto see it in action.

这是一个小提琴,可以看到它的实际效果。

UPDATE
Note that you can call functionLogger.addLoggingToNamespace(window);to add logging to all global functions at the time of the call. Also, if you really want, you can traverse the tree to find any functions and update them accordingly. The one downfall of this method is that it only works on functions that exist at the time. Thus, it's still not the greatest solution, but it's a LOT less work than adding logging statements by hand :)

更新
请注意,您可以在调用时调用functionLogger.addLoggingToNamespace(window);以将日志记录添加到所有全局函数。此外,如果您真的需要,您可以遍历树以查找任何函数并相应地更新它们。这种方法的一个缺点是它只适用于当时存在的函数。因此,它仍然不是最好的解决方案,但比手动添加日志语句要少很多工作:)

回答by Jeff

This is called profiling and Chrome and Firebug have it built in. In Chrome developer Tools, go to the profiles tab and click the record (circle) button. Perform your ajax and after your response, click the record button again to stop. The results of the profiling will appear in the right pane.

这称为分析,Chrome 和 Firebug 内置了它。在Chrome 开发人员工具中,转到配置文件选项卡并单击记录(圆圈)按钮。执行您的 ajax 并在您的响应后,再次单击记录按钮停止。分析结果将显示在右侧窗格中。

Note, this is going to give you everythingso if you are using a library like jQuery, the vast majority of the function calls are going to be garbage to you. I've tried this a few times and I find it is much more helpful to do the console.log('inside <method>')thing.

注意,这会给你一切,所以如果你使用像 jQuery 这样的库,绝大多数函数调用对你来说都是垃圾。我已经尝试了几次,我发现做这console.log('inside <method>')件事更有帮助。

回答by Peter Tseng

A variation on Briguy37's solution, I wrote one that accepts a function to call before each method. It also works with ECMAScript 6 classes, where methods are not enumerated by for...in. I'm using it to modify Object prototypes, to add logging to all new instances of my object.

作为 Briguy37 解决方案的一种变体,我编写了一个接受在每个方法之前调用的函数的方法。它还适用于 ECMAScript 6 类,其中方法不是由 for...in 枚举的。我用它来修改对象原型,为我的对象的所有新实例添加日志记录。

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

回答by Jason Sperske

Maybe you can have JavaScript do some of the work of adding console.log for you:

也许你可以让 JavaScript 为你做一些添加 console.log 的工作:

Adding console.log to every function automatically

自动将 console.log 添加到每个函数

Also this blog by Paul Irish might help:

Paul Irish 的这个博客也可能有帮助:

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

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

It includes a link to some JavaScript specifically targeted at logging arguments:

它包含指向一些专门针对日志参数的 JavaScript 的链接:

http://pastie.org/1033665

http://pastie.org/1033665

回答by diyism

Give a try to diyism_trace_for_javascript.htm:

试试 diyism_trace_for_javascript.htm:

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

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

View logs in console tab of chrome or firefox

在 chrome 或 firefox 的控制台选项卡中查看日志

回答by killebytes

I just found out that you could do that with a console.trace()

我刚刚发现你可以用一个 console.trace()

回答by Jean-Fran?ois Beauchamp

I've used @Briguy37's solution with an improvement. In my case, I did not want to trace functions from some libraries, so I added some code to exclude them. Here is how it is used:

我使用了@Briguy37 的解决方案进行了改进。就我而言,我不想跟踪某些库中的函数,因此我添加了一些代码来排除它们。以下是它的使用方法:

  • First, include the definition of the functions you don't want to trace;
  • excludeLoggingToNamespace to list the functions defined up to now and exclude them;
  • Include the definition of the functions you want to trace;
  • Call addLoggingToNamespace to add the logging capability to the functions defined in the above step.
  • 首先,包括您不想跟踪的函数的定义;
  • excludeLoggingToNamespace 列出到目前为止定义的函数并排除它们;
  • 包括要跟踪的函数的定义;
  • 调用 addLoggingToNamespace 将日志记录功能添加到上述步骤中定义的函数。

Example:

例子:

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

Here is the code I added to @Briguy37's solution:

这是我添加到@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;
                }
            }
        }; 

And I had to modify @Briguy37's addLoggingToNamespace method to take into accound the excludedFunctions hash:

我不得不修改@Briguy37 的 addLoggingToNamespace 方法以考虑到 excludeFunctions 哈希:

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