Javascript 如何在node.js中获取调用方函数的文件路径?
以下是三个文件中的一些示例代码:Javascript 如何在node.js中获取调用方函数的文件路径?,javascript,node.js,Javascript,Node.js,以下是三个文件中的一些示例代码: // foo.js var myFunc = require("./myFunc"); function foo(){ myFunc("message"); } // bar.js var myFunc = require("./myFunc"); function bar(){ myFunc("message"); } // myFunc.js module.exports = myFunc; function myFunc(arg1){
// foo.js
var myFunc = require("./myFunc");
function foo(){
myFunc("message");
}
// bar.js
var myFunc = require("./myFunc");
function bar(){
myFunc("message");
}
// myFunc.js
module.exports = myFunc;
function myFunc(arg1){
console.log(arg1);
// Here I need the file path of the caller function
// For example, "/path/to/foo.js" and "/path/to/bar.js"
}
我需要动态地获取调用函数的文件路径,而不需要传递任何额外的参数,因为
myFunc
您需要处理v8
的内部工作。请参阅:
我在中的一些代码上进行了一个小测试,它似乎可以工作。你最终会得到一条绝对路径
// omfg.js
module.exports = omfg
function omfg() {
var caller = getCaller()
console.log(caller.filename)
}
// private
function getCaller() {
var stack = getStack()
// Remove superfluous function calls on stack
stack.shift() // getCaller --> getStack
stack.shift() // omfg --> getCaller
// Return caller's caller
return stack[1].receiver
}
function getStack() {
// Save original Error.prepareStackTrace
var origPrepareStackTrace = Error.prepareStackTrace
// Override with function that just returns `stack`
Error.prepareStackTrace = function (_, stack) {
return stack
}
// Create a new `Error`, which automatically gets `stack`
var err = new Error()
// Evaluate `err.stack`, which calls our new `Error.prepareStackTrace`
var stack = err.stack
// Restore original `Error.prepareStackTrace`
Error.prepareStackTrace = origPrepareStackTrace
// Remove superfluous function call on stack
stack.shift() // getStack --> Error
return stack
}
以及包括omfg
模块的测试:
#!/usr/bin/env node
// test.js
var omfg = require("./omfg")
omfg()
您将在控制台上获得test.js
的绝对路径
解释 这与其说是一个“node.js”问题,不如说是一个“v8”问题 见: 在
error
参数中添加stack
属性,默认情况下,该属性的计算结果为字符串
(通过)。如果Error.prepareStackTrace(Error,structuredStackTrace)
是函数
,则调用它而不是FormatStackTrace
因此,我们可以用我们自己的函数覆盖Error.prepareStackTrace
,该函数将返回我们想要的任何内容——在本例中,只返回structuredStackTrace
参数
然后,
structuredStackTrace[1]。receiver
是一个表示调用者的对象。或者,您可以使用module.parent.filename
来获取需要模块的模块的绝对路径,而不是摆弄V8引擎的内部工作。如下所示:
请记住,模块是缓存的,因此如果任何其他文件需要它并调用它,它将始终是第一个导入程序的路径。我的2美分:
假设您有一个log
对象,它将调用者的文件名作为额外信息添加到控制台,例如log
响应log.info(msg)
,并将执行类似以下操作:
// my_module.js
log.info('hello')
$> [[my_module.js]] hello
info
将是:
info: function(msg) {
let caller = path.basename(module.parent.filename);
console.log(`[[${caller}]] ${msg}`);
}
问题:如前所述,parent.filename
将返回首先需要模块的用户,而不是调用方本身
备选方案:是一个模块,可实现以下功能:
const stackTrace = require('stack-trace');
...
info: function(msg) {
let caller = path.basename(stackTrace.get()[0].getFilename());
console.log(`[[${caller}]] ${msg}`);
}
要点:stackTrace.get()[0]
返回响应的最后一个(只是其中的一部分)
getFileName()
getColumnNumber()
getFunctionName()
getLineNumber()
getMethodName()
v8
术语中)。而stackman
提供了带有自定义函数和行为的调用站点。源上下文等。这是围绕呼叫站点线路的代码行。如果可用,还可以使用源地图
stackman的问题在于它异步返回调用站点。当从调试器运行时,它不是特别有用
以下是我使用的一些代码,您可能会发现它们很有用:
var callsites = require('callsites');
var util = require('util');
var path = require('path');
function printStackTrace() {
callsites().slice(1).forEach(function(cs) {
printCallSite(cs);
});
}
function printCallSite(cs) {
console.log(util.format('%s:%i',
path.relative(process.cwd(), cs.getFileName()),
cs.getLineNumber()));
console.log(' getTypeName(): ' + cs.getTypeName());
console.log(' getFunctionName(): ' + cs.getFunctionName());
console.log(' getMethodName(): ' + cs.getMethodName());
// console.log(' getEvalOrigin(): ' + cs.getEvalOrigin());
// console.log(' isTopLevel(): ' + (cs.isTopLevel ? cs.isTopLevel() : null));
// console.log(' isEval(): ' + cs.isEval());
// console.log(' isNative(): ' + cs.isNative());
// console.log(' isConstructor(): ' + cs.isConstructor());
}
function getCallSiteIndexes(cond) {
var cond = cond || function() { return true; };
var options = arguments[1] || {};
var css = options['callsites'] || callsites().slice(1);
var r = [];
for (var i = 0; i < css.length; i++) {
var cs = css[i];
if (cond(cs)) {
if (options['first'])
return i;
r.push(i);
}
}
return options['first'] ? null : r;
}
function getFirstCallSiteIndex(cond) {
var css = callsites().slice(1);
return getCallSiteIndexes(cond, {first: true, callsites: css});
}
function getCallSites(cond) {
var options = arguments[1] || {};
var css = options['callsites'] || callsites().slice(1);
var indexes = getCallSiteIndexes(cond,
Object.assign({}, {callsites: css}, options));
if (options['first'])
return css[indexes];
return indexes.map(function(i) {
return css[i];
});
}
function getFirstCallSite(cond) {
var css = callsites().slice(1);
return getCallSites(cond, {first: true, callsites: css});
}
fucntion f() {
var firstCS = callsites()[0];
var runAsChildCSIndex = getFirstCallSiteIndex(function(cs) {
return cs.getFileName() == firstCS.getFileName() && cs.getFunctionName() == 'Compiler.runAsChild';
});
if (runAsChildCSIndex) {
printCallSite(callsites()[runAsChildCSIndex + 1]);
} else {
var compilerRunCS = getFirstCallSite(function(cs) {
return cs.getFileName() == firstCS.getFileName() && cs.getFunctionName() == 'Compiler.run';
});
printCallSite(compilerRunCS);
}
...
var callsites=require('callsites');
var util=require('util');
var path=require('path');
函数printStackTrace(){
callsites().slice(1).forEach(函数(cs){
打印调用站点(cs);
});
}
函数printCallSite(cs){
console.log(util.format(“%s:%i”),
path.relative(process.cwd(),cs.getFileName()),
cs.getLineNumber());
log('getTypeName():'+cs.getTypeName());
log('getFunctionName():'+cs.getFunctionName());
log('getMethodName():'+cs.getMethodName());
//log('getEvalOrigin():'+cs.getEvalOrigin());
//log('isTopLevel():'+(cs.isTopLevel?cs.isTopLevel():null));
//log('isEval():'+cs.isEval());
//log('isNative():'+cs.isNative());
//log('isConstructor():'+cs.isConstructor());
}
函数getCallSiteIndexes(cond){
var cond=cond | | function(){return true;};
var options=参数[1]|{};
var css=options['callsites']| | callsites().slice(1);
var r=[];
for(var i=0;i
获取节点中调用方函数路径的唯一方法是通过堆栈跟踪(忘记外部库):
如果您不想使用第三方库,可以这样做: 函数getFileCallerURL():字符串{ 常量错误:错误=新错误(); 常量堆栈:字符串[]=错误。堆栈?.split('\n')作为字符串[]; 常量数据:字符串=堆栈[3]; 康斯特费
var callsites = require('callsites');
var util = require('util');
var path = require('path');
function printStackTrace() {
callsites().slice(1).forEach(function(cs) {
printCallSite(cs);
});
}
function printCallSite(cs) {
console.log(util.format('%s:%i',
path.relative(process.cwd(), cs.getFileName()),
cs.getLineNumber()));
console.log(' getTypeName(): ' + cs.getTypeName());
console.log(' getFunctionName(): ' + cs.getFunctionName());
console.log(' getMethodName(): ' + cs.getMethodName());
// console.log(' getEvalOrigin(): ' + cs.getEvalOrigin());
// console.log(' isTopLevel(): ' + (cs.isTopLevel ? cs.isTopLevel() : null));
// console.log(' isEval(): ' + cs.isEval());
// console.log(' isNative(): ' + cs.isNative());
// console.log(' isConstructor(): ' + cs.isConstructor());
}
function getCallSiteIndexes(cond) {
var cond = cond || function() { return true; };
var options = arguments[1] || {};
var css = options['callsites'] || callsites().slice(1);
var r = [];
for (var i = 0; i < css.length; i++) {
var cs = css[i];
if (cond(cs)) {
if (options['first'])
return i;
r.push(i);
}
}
return options['first'] ? null : r;
}
function getFirstCallSiteIndex(cond) {
var css = callsites().slice(1);
return getCallSiteIndexes(cond, {first: true, callsites: css});
}
function getCallSites(cond) {
var options = arguments[1] || {};
var css = options['callsites'] || callsites().slice(1);
var indexes = getCallSiteIndexes(cond,
Object.assign({}, {callsites: css}, options));
if (options['first'])
return css[indexes];
return indexes.map(function(i) {
return css[i];
});
}
function getFirstCallSite(cond) {
var css = callsites().slice(1);
return getCallSites(cond, {first: true, callsites: css});
}
fucntion f() {
var firstCS = callsites()[0];
var runAsChildCSIndex = getFirstCallSiteIndex(function(cs) {
return cs.getFileName() == firstCS.getFileName() && cs.getFunctionName() == 'Compiler.runAsChild';
});
if (runAsChildCSIndex) {
printCallSite(callsites()[runAsChildCSIndex + 1]);
} else {
var compilerRunCS = getFirstCallSite(function(cs) {
return cs.getFileName() == firstCS.getFileName() && cs.getFunctionName() == 'Compiler.run';
});
printCallSite(compilerRunCS);
}
...
function getCallerFilePath(path) {
let stack = new Error().stack.split('\n')
return stack[2].slice(
stack[2].lastIndexOf('(')+1,
stack[2].lastIndexOf('.js')+3
)
}