【问题标题】:Nodejs: get filename of caller functionNodejs:获取调用者函数的文件名
【发布时间】:2013-05-22 17:11:29
【问题描述】:

我想知道如何获取函数调用者的绝对路径?

这么说吧:

在文件a.js 我打电话给b()b() 是文件b.js 中定义的函数。 a.js需要b。那么如何从节点中的b.js 获取a.js 的绝对路径呢?

【问题讨论】:

标签: javascript node.js


【解决方案1】:

无法恢复 prepareStackTrace 函数可能会导致问题。这是一个消除副作用的示例

function _getCallerFile() {
    var originalFunc = Error.prepareStackTrace;

    var callerfile;
    try {
        var err = new Error();
        var currentfile;

        Error.prepareStackTrace = function (err, stack) { return stack; };

        currentfile = err.stack.shift().getFileName();

        while (err.stack.length) {
            callerfile = err.stack.shift().getFileName();

            if(currentfile !== callerfile) break;
        }
    } catch (e) {}

    Error.prepareStackTrace = originalFunc; 

    return callerfile;
}

【讨论】:

  • 太棒了!我试图解决一个与此相关的问题好几个小时。重新分配原始函数修复了一切。
  • 嗨,这个解决方案工作正常......但是如果在回调中调用了一个函数,那么它将获得触发回调的文件的名称
  • 使用finally重置Error.prepareStackTrace不是更安全吗?
【解决方案2】:

这是一个如何使用堆栈跟踪在节点中查找调用者文件的示例

function _getCallerFile() {
    var filename;

    var _pst = Error.prepareStackTrace
    Error.prepareStackTrace = function (err, stack) { return stack; };
    try {
        var err = new Error();
        var callerfile;
        var currentfile;

        currentfile = err.stack.shift().getFileName();

        while (err.stack.length) {
            callerfile = err.stack.shift().getFileName();

            if(currentfile !== callerfile) {
                filename = callerfile;
                break;
            }
        }
    } catch (err) {}
    Error.prepareStackTrace = _pst;

    return filename;
}

【讨论】:

  • 重要!向下滚动一点,有更新的答案没有与这个相同的潜在错误和陷阱(尽管我确实对其进行了编辑以省略最严重的错误)。 @Christoph's 似乎是最好的。
【解决方案3】:

这里没有完全回答问题 但有些人可能会欣赏这些信息。

使用 NodeJS 和 Forever(-monitor), 以下包含启动进程的文件名:

process.mainModule.filename

虽然没有尝试过很多用途™。

这似乎是一个相当不错的解释:https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi

【讨论】:

  • 肯定没有回答这个问题,但这对我有帮助。谢谢!
【解决方案4】:

使用https://github.com/sindresorhus/callsites

如果您使用第一个答案,您可能会与其他试图做同样事情的库混淆。例如:https://github.com/facebook/jest/issues/5303

【讨论】:

    【解决方案5】:

    如果你需要的调用者文件没有​​在实现它的文件中被调用——就像在 OP 的场景中一样——你可以写:

    function _getCallerFile()
    {
        const prepareStackTraceOrg = Error.prepareStackTrace;
        const err = new Error();
    
        Error.prepareStackTrace = (_, stack) => stack;
    
        const stack = err.stack;
    
        Error.prepareStackTrace = prepareStackTraceOrg;
    
        return stack[1].getFileName();
    }
    

    try...catch 是不必要的,因为如果将 Error 分配给变量,则不会抛出它。

    此外,如果您想在多个项目中使用_getCallerFile,您可能希望将它放在自己的文件中,但随后您将获得调用_getCallerFile 的文件的名称。 在这种情况下,只需写return stack[2].getFileName();,即。 e.在调用堆栈中再退一步。

    如果您使用 TypeScript,则必须编写 const stack = err.stack as unknown as NodeJS.CallSite[];,因为 Error.stack 的声明类型是 string,但我们的 prepareStackTrace 函数返回一个 NodeJS.CallSite 对象数组。

    仅供参考:NodeJS.CallSite 有更多有趣的方法,例如。 G。 getFunctionName.

    更新

    在分配 lambda 之前,我注意到 Error.prepareStackTrace === undefined。如果您不信任我,只需将console.log('prepareStackTraceOrg:', prepareStackTraceOrg); 添加到函数中即可。 因此,我们可以简化函数:

    function _getCallerFile()
    {
        const err = new Error();
    
        Error.prepareStackTrace = (_, stack) => stack;
    
        const stack = err.stack;
    
        Error.prepareStackTrace = undefined;
    
        return stack[1].getFileName();
    }
    

    【讨论】:

      【解决方案6】:

      npm caller package 有一个函数可以返回调用者的路径和文件名。

      【讨论】:

      • 调试时调用者包返回internal/module.js。
      • github上发布的示例也返回与节点v8.11.1上的调用者相同的“internal/module.js”
      【解决方案7】:

      在 JavaScript 中获取堆栈跟踪非常困难。我发现的最好方法是抛出一个错误,捕获它,从Error.getStack() 获取堆栈(并非在所有浏览器中都实现,这意味着你是 IE。)并格式化输出。

      每个堆栈帧都会为您提供文件路径、行号和函数名称。 Webkit 甚至支持参数,但当我上次检查时,它还没有工作。

      然后就是跨不同事件跟踪代码的问题。

      我实际上写了一篇关于此的博客文章:http://fritsvancampen.wordpress.com/2013/03/28/error-handling-in-javascript-a-better-way/

      【讨论】:

      • 尝试 { throw new Error(); } catch(e) { console.log(JSON.stringify(e)); } 不适用于 nodejs
      • 您不能对原生对象进行 JSON 编码。为什么你甚至想这样做? :S
      【解决方案8】:

      您可以使用require.resolve(module) 来确定模块的完整路径:

      var path = require.resolve("a");
      
      //or
      
      var path = require.resolve("./a.js");
      

      【讨论】:

      • 调用者并不总是预先确定的,所以:这种方式行不通
      • Resolve 用于合并路径,或遍历路径。查找调用者的补丁是不同的。
      猜你喜欢
      • 2019-09-07
      • 2016-04-07
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多