Javascript 遍历arguments.callee.caller会导致无限循环
假设我想获取某种堆栈跟踪,获取在当前函数之前调用的所有函数的名称 我是这样做的:Javascript 遍历arguments.callee.caller会导致无限循环,javascript,node.js,Javascript,Node.js,假设我想获取某种堆栈跟踪,获取在当前函数之前调用的所有函数的名称 我是这样做的: var callee; var caller; var _args = arguments; var check = 0; do { check++; callee = _args.callee; caller =
var callee;
var caller;
var _args = arguments;
var check = 0;
do {
check++;
callee = _args.callee;
caller = callee.caller;
var msg = 'Check ' + check + ' - ' + callee.name
+ ' has been called by: ' + caller.name;
console.log(msg);
if (caller) {
// Get this caller's arguments
_args = caller.arguments;
} else {
reached_end = true;
}
} while (!reached_end);
大多数情况下,这很好用。但有时它会陷入无限循环,我想知道:这怎么可能?我能做些什么呢
以下是我的无限循环的输出:
Check 1 - __parent__ has been called by: add
Check 2 - add has been called by: afterComponentStartup
Check 3 - afterComponentStartup has been called by: _launchComponents [arg0:"startup"]
Check 4 - _launchComponents has been called by: beforeActionNext
Check 5 - beforeActionNext has been called by: beforeAction
Check 6 - beforeAction has been called by: afterComponentInitialize
Check 7 - afterComponentInitialize has been called by: _launchComponents [arg0:"startup"]
Check 8 - _launchComponents has been called by: beforeActionNext
Check 9 - beforeActionNext has been called by: beforeAction
Check 10 - beforeAction has been called by: afterComponentInitialize
Check 11 - afterComponentInitialize has been called by: _launchComponents [arg0:"startup"]
Check 12 - _launchComponents has been called by: beforeActionNext
Check 13 - beforeActionNext has been called by: beforeAction
Check 14 - beforeAction has been called by: afterComponentInitialize
Check 15 - afterComponentInitialize has been called by: _launchComponents [arg0:"startup"]
Check 16 - _launchComponents has been called by: beforeActionNext
Check 17 - beforeActionNext has been called by: beforeAction
Check 18 - beforeAction has been called by: afterComponentInitialize
Check 19 - afterComponentInitialize has been called by: _launchComponents [arg0:"startup"]
Check 20 - _launchComponents has been called by: beforeActionNext
Check 21 - beforeActionNext has been called by: beforeAction
Check 22 - beforeAction has been called by: afterComponentInitialize
Check 23 - afterComponentInitialize has been called by: _launchComponents [arg0:"startup"]
Check 24 - _launchComponents has been called by: beforeActionNext
Check 25 - beforeActionNext has been called by: beforeAction
Check 26 - beforeAction has been called by: afterComponentInitialize
您需要在数组中添加调用者,并检查下一个调用者是否在数组中。如果是这样,那么就有一个循环或递归调用结构。试试这个:
var args = arguments;
var callee = args.callee;
var caller = callee.caller;
var stack = [callee];
while (caller) {
if (stack.indexOf(caller) < 0) {
stack.push(caller);
args = caller.arguments;
callee = args.callee;
caller = callee.caller;
} else break;
}
console.log(stack);
var args=参数;
var callee=args.callee;
var caller=callee.caller;
var stack=[callee];
while(呼叫者){
if(stack.indexOf(调用者)<0){
stack.push(调用方);
args=caller.arguments;
被调用方=args.callee;
caller=callee.caller;
}否则就断了;
}
控制台日志(堆栈);
您需要在数组中添加呼叫者,并检查下一个呼叫者是否在数组中。如果是这样,那么就有一个循环或递归调用结构。试试这个:
var args = arguments;
var callee = args.callee;
var caller = callee.caller;
var stack = [callee];
while (caller) {
if (stack.indexOf(caller) < 0) {
stack.push(caller);
args = caller.arguments;
callee = args.callee;
caller = callee.caller;
} else break;
}
console.log(stack);
var args=参数;
var callee=args.callee;
var caller=callee.caller;
var stack=[callee];
while(呼叫者){
if(stack.indexOf(调用者)<0){
stack.push(调用方);
args=caller.arguments;
被调用方=args.callee;
caller=callee.caller;
}否则就断了;
}
控制台日志(堆栈);
arguments.callee.caller指向函数引用,每个调用堆栈中每个函数只存在一个函数引用
每次调用函数时,都会设置调用者
属性,这意味着如果同一函数在调用堆栈中被多次调用,就像递归函数一样,先前的值将被重置,并且调用者
现在将指向自身。这就是造成无限循环的原因
因此,在您的算法中,如果您到达一个点,
callee===callee.caller
,您需要中断以避免这种情况发生。参数。callee.caller
指向函数引用,它在每个调用堆栈中只存在一个函数
每次调用函数时,都会设置调用者
属性,这意味着如果同一函数在调用堆栈中被多次调用,就像递归函数一样,先前的值将被重置,并且调用者
现在将指向自身。这就是造成无限循环的原因
因此,在您的算法中,如果您到达一个点,
callee===callee.caller
,您需要中断以避免这种情况发生。我找到了一种方法,可以将状态信息(在本例中为var.ua(Object))传递到递归函数的调用堆栈中
而不是
var fwa.animatedJavascriptControlCenter = {
...
,
scanElements : function (el, scanResult) {
// a function that walks the DOM tree to find elements that require molding by my js framework
if (!scanResult) scanResult={};
if (el.tagName.toLowerCase()!='svg') {
if (conditions_for_this_element_met(el)) {
scanResults[el.id] = el;
};
if (el.children.length>0) {
for (var i=0; i < el.children.length; i++) {
if (el.children[i].tagName.toUpperCase()!=='IFRAME') {
scanResult = fwa.animatedJavascriptControlCenter.scanElements(el.children[i], scanResult);
}
}
}
}
return scanResult;
},
...
}
仅供参考:此代码取自我的js框架,并将成为其hipLog组件的一部分,该组件旨在向您显示任何用户操作(如单击、悬停或页面加载)的完整执行路径(无论是否往返于服务器和/或setTimeout())。我找到了传递状态信息的方法(本例中为var.ua(Object))进入递归函数的调用堆栈 而不是
var fwa.animatedJavascriptControlCenter = {
...
,
scanElements : function (el, scanResult) {
// a function that walks the DOM tree to find elements that require molding by my js framework
if (!scanResult) scanResult={};
if (el.tagName.toLowerCase()!='svg') {
if (conditions_for_this_element_met(el)) {
scanResults[el.id] = el;
};
if (el.children.length>0) {
for (var i=0; i < el.children.length; i++) {
if (el.children[i].tagName.toUpperCase()!=='IFRAME') {
scanResult = fwa.animatedJavascriptControlCenter.scanElements(el.children[i], scanResult);
}
}
}
}
return scanResult;
},
...
}
仅供参考:此代码取自我的js框架,并将成为其hipLog组件的一部分,该组件旨在向您显示任何用户操作(如单击、悬停或页面加载)的完整执行路径(有无往返服务器和/或setTimeout())?
// call this just after _completely_ defining yourFrameworkRootObject and yourSiteCodeRootObject
tracer.traceAll (yourFrameworkRootObject, true);
tracer.traceAll (yourSiteCodeRootObject, true);