Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/450.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 遍历arguments.callee.caller会导致无限循环_Javascript_Node.js - Fatal编程技术网

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