Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/470.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/32.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 如何避免;超过最大调用堆栈大小;例外?_Javascript_C#_Recursion - Fatal编程技术网

Javascript 如何避免;超过最大调用堆栈大小;例外?

Javascript 如何避免;超过最大调用堆栈大小;例外?,javascript,c#,recursion,Javascript,C#,Recursion,我有下一个代码生成网站地图树的URL列表。 C#模型: 生成节点列表的C#方法 private static List<Node> ExtractNode(List<string> Urls) { List<Node> nodeList = new List<Node>(); foreach (string itm in Urls) { string[] arr =

我有下一个代码生成网站地图树的URL列表。 C#模型:

生成节点列表的C#方法

private static List<Node> ExtractNode(List<string> Urls)
    {
        List<Node> nodeList = new List<Node>();

        foreach (string itm in Urls)
        {
            string[] arr = itm.Split('/');
            int index = -1;

            foreach (string node in arr)
            {
                index += 1;
                if (index == 0)
                {
                    Node rootNode = new Node(node, "");
                    if (!nodeList.Exists(x => x.Child == rootNode.Child & x.Parent == rootNode.Parent))
                    {
                        rootNode.IsRoot = true;
                        nodeList.Add(rootNode);
                    }
                }
                else
                {
                    Node childNode = new Node(node, arr[index - 1].ToString());
                    {
                        if (!nodeList.Exists(x => x.Child == childNode.Child & x.Parent == childNode.Parent))
                        {
                            nodeList.Add(childNode);
                        }
                    }
                }
            }
        }
        return nodeList;
    }
私有静态列表提取节点(列表URL)
{
列表节点列表=新列表();
foreach(URL中的字符串itm)
{
字符串[]arr=itm.Split('/');
int指数=-1;
foreach(arr中的字符串节点)
{
指数+=1;
如果(索引==0)
{
节点rootNode=新节点(节点“”);
如果(!nodeList.Exists(x=>x.Child==rootNode.Child&x.Parent==rootNode.Parent))
{
rootNode.IsRoot=true;
添加(rootNode);
}
}
其他的
{
Node childNode=新节点(节点,arr[index-1].ToString());
{
如果(!nodeList.Exists(x=>x.Child==childNode.Child&x.Parent==childNode.Parent))
{
添加(子节点);
}
}
}
}
}
返回节点列表;
}
Javascript代码。下一个函数获取节点列表:

function makeTree(nodes) {
var roots = [];
for (var i = 0; i < nodes.length; i++) {
    if (nodes[i].IsRoot) {
        roots.push(nodes[i].Child);
    }
}
var trees = "";
for (var j = 0; j < roots.length; j++) {
    trees += "<div class='sitemapRoot'><ul><li>" + getChildren(roots[j], nodes) + "</li></ul></div>";
}
return trees;
}
函数生成树(节点){
var根=[];
对于(var i=0;i
  • ”+getChildren(根[j],节点)+“
  • ”; } 归还树木; }
    下一个递归调用:

    function getChildren(root, nodes) {
    var result = "";
    var index = 0;
    for (var i = 0; i < nodes.length; i++) {
        if (nodes[i].Parent == root) {
            index += 1;
        }
    }
    
    if (index > 0) {
        var RootHeader = "";
        for (var j = 0; j < nodes.length; j++) {
            if (nodes[j].IsRoot & root == nodes[j].Child) {
                RootHeader = nodes[j].Child;
            }
        }
        result += RootHeader + "<ul>\n";
        for (var k = 0; k < nodes.length; k++) {
            if (nodes[k].IsRoot & root == nodes[k].Child) {
                RootHeader = nodes[k].Child;
            }
            if (nodes[k].Parent == root) {
                result += "<ul><li>" + nodes[k].Child + getChildren(nodes[k].Child, nodes) + "</li></ul>\n";
            }
        }
        result += "</ul>\n";
        return result;
    }
    return "";
    }
    
    函数getChildren(根,节点){ var结果=”; var指数=0; 对于(var i=0;i0){ var RootHeader=“”; 对于(var j=0;j\n”; 对于(var k=0;k
  • ”+节点[k]。子节点+getChildren(节点[k]。子节点,节点)+“
  • \n”; } } 结果+=“\n”; 返回结果; } 返回“”; } 这段代码适用于一小部分数据。但当我尝试传递500个节点的列表时,我会遇到下一个错误:

    未捕获范围错误:超过最大调用堆栈大小 在getChildren(treeGenerator.js:371)


    因此,问题是如何优化代码以避免此错误?

    有两种方法可以解决此问题。在使用递归函数时,您总是需要担心调用堆栈的大小。如果您认为这是一个问题,那么您需要进行异步或重构以避免递归。这些不一定是最优化的答案,但希望它们能让你开始

    非递归函数

    function makeTree(nodes) {
        var roots = [],
            limbs = [],
            i, j;
    
        //go through all of the nodes and link the parent/children.
        for (i = 0; i < nodes.length; i++) {
            for (j = i + 1; j < nodes.length; j++) {//only look at the rest of the elements to increase performance
                if (nodes[i].Child == nodes[j].Parent) {
                    nodes[i].children = (nodes[i].children || []);
                    nodes[i].children.push(nodes[j]);
                    nodes[j].parentNode = nodes[i];
                }
            }
            for (j = 0; j < limbs.length; j++) {//look through the limbs to see if one of them is my child.
                if (nodes[i].Child == limbs[j].Parent) {
                    nodes[i].children = (nodes[i].children || []);
                    nodes[i].children.push(limbs[j]);
                    limbs[j].parentNode = nodes[i];
                    limbs.splice(j--, 1);//remove from the list since I can only have 1 parent.
                }
            }
            //I have all of my children.
            if (nodes[i].IsRoot) {
                roots.push(nodes[i]);
            }else if(!nodes[i].parentNode){
                //I don't know my parent so I'm a limb.
                limbs.push(node);
            }
    
        }
        //now that everyone knows their parent and their children, we'll assemble the html by looking at all of the leafs first and working way up the tree.
        i = 0;
        while(nodes.length > 0){
            if(!nodes[i].children || nodes[i].childHtml){
                //I'm either a leaf or I have my child's html.
                var node = nodes[i];
                node.html = node.Child + (node.childHtml? "<ul>" + node.childHtml + "</ul>" : "");
                node.childHtml = null;//don't need this anymore.
                if(node.parentNode){
                    //let's check to see if my siblings are complete
                    var ready = true,
                        childHtml = "";
                    for(var j = 0; j < node.parentNode.children.length; j++){
                        if(node.parentNode.children[j].html == null){
                            ready = false;//I don't know this html yet so skip it for now.
                            break;
                        }else{
                            childHtml += "<li>" + node.parentNode.children[j].html + "</li>";//go ahead and try to create the list of children.
                        }
                    }
                    if(ready){
                        //all of siblings are complete, so update parent.
                        node.parentNode.childHtml = childHtml;
                        node.parentNode.children = null;//remove reference for cleanup.
                    }
                }
                nodes.splice(i, 1);//remove from the list since I have my html.
            }else{
                i++;//look at the next node in the list.
            }
            if(i >= nodes.length){
                i = 0;//since we are splicing and going through the list multiple times (possibly), we'll set the index back to 0.
            }
        }
    
        //every node knows it's html, so build the full tree.
        var trees = "";
        for (var j = 0; j < roots.length; j++) {
            trees += "<div class='sitemapRoot'><ul><li>" + roots[j].html + "</li></ul></div>";
        }
        return trees;
    }
    
    function makeTreeAsync(nodes, callback) {
        var roots = [],
            numRoots = 0;
        for (var i = 0; i < nodes.length; i++) {
            if (nodes[i].IsRoot) {
                numRoots++;
                getChildrenAsync(nodes[i], nodes, create);
            }
        }
        function create(child){
            roots.push(child);
            if(roots.length === numRoots){
                var trees = "";
                for (var j = 0; j < roots.length; j++) {
                    trees += "<div class='sitemapRoot'><ul><li>" + roots[j].html + "</li></ul></div>";
                }
                callback(trees);
            }
        }   
    }
    function getChildrenAsync(root, nodes, callback) {
        var result = "";
        var index = 0;
        var children = [];
        for (var i = 0; i < nodes.length; i++) {
            if (nodes[i].Parent == root.Child) {
                index += 1;
                getChild(i);
            }
        }
    
        if (index == 0) {
            root.html = root.Child;
            callback(root);
        }
        function getChild(x){
            setTimeout(function(){
                getChildrenAsync(nodes[x], nodes, createHtml);
            });
        }
        function createHtml(node){
            children.push(node);
            if(children.length === index){      
                var result = root.Child;
                if(children.length){
                    result += "<ul>"
                    for (var j = 0; j < children.length; j++) {
                        result += "<li>" + children[j].html + "</li>";
                    }
                    result += "</ul>";
                }
                root.html = result;
                callback(root);
            }
        }
    }
    

    有两种方法可以解决此问题。在使用递归函数时,您总是需要担心调用堆栈的大小。如果您认为这是一个问题,那么您需要进行异步或重构以避免递归。这些不一定是最优化的答案,但希望它们能让你开始

    非递归函数

    function makeTree(nodes) {
        var roots = [],
            limbs = [],
            i, j;
    
        //go through all of the nodes and link the parent/children.
        for (i = 0; i < nodes.length; i++) {
            for (j = i + 1; j < nodes.length; j++) {//only look at the rest of the elements to increase performance
                if (nodes[i].Child == nodes[j].Parent) {
                    nodes[i].children = (nodes[i].children || []);
                    nodes[i].children.push(nodes[j]);
                    nodes[j].parentNode = nodes[i];
                }
            }
            for (j = 0; j < limbs.length; j++) {//look through the limbs to see if one of them is my child.
                if (nodes[i].Child == limbs[j].Parent) {
                    nodes[i].children = (nodes[i].children || []);
                    nodes[i].children.push(limbs[j]);
                    limbs[j].parentNode = nodes[i];
                    limbs.splice(j--, 1);//remove from the list since I can only have 1 parent.
                }
            }
            //I have all of my children.
            if (nodes[i].IsRoot) {
                roots.push(nodes[i]);
            }else if(!nodes[i].parentNode){
                //I don't know my parent so I'm a limb.
                limbs.push(node);
            }
    
        }
        //now that everyone knows their parent and their children, we'll assemble the html by looking at all of the leafs first and working way up the tree.
        i = 0;
        while(nodes.length > 0){
            if(!nodes[i].children || nodes[i].childHtml){
                //I'm either a leaf or I have my child's html.
                var node = nodes[i];
                node.html = node.Child + (node.childHtml? "<ul>" + node.childHtml + "</ul>" : "");
                node.childHtml = null;//don't need this anymore.
                if(node.parentNode){
                    //let's check to see if my siblings are complete
                    var ready = true,
                        childHtml = "";
                    for(var j = 0; j < node.parentNode.children.length; j++){
                        if(node.parentNode.children[j].html == null){
                            ready = false;//I don't know this html yet so skip it for now.
                            break;
                        }else{
                            childHtml += "<li>" + node.parentNode.children[j].html + "</li>";//go ahead and try to create the list of children.
                        }
                    }
                    if(ready){
                        //all of siblings are complete, so update parent.
                        node.parentNode.childHtml = childHtml;
                        node.parentNode.children = null;//remove reference for cleanup.
                    }
                }
                nodes.splice(i, 1);//remove from the list since I have my html.
            }else{
                i++;//look at the next node in the list.
            }
            if(i >= nodes.length){
                i = 0;//since we are splicing and going through the list multiple times (possibly), we'll set the index back to 0.
            }
        }
    
        //every node knows it's html, so build the full tree.
        var trees = "";
        for (var j = 0; j < roots.length; j++) {
            trees += "<div class='sitemapRoot'><ul><li>" + roots[j].html + "</li></ul></div>";
        }
        return trees;
    }
    
    function makeTreeAsync(nodes, callback) {
        var roots = [],
            numRoots = 0;
        for (var i = 0; i < nodes.length; i++) {
            if (nodes[i].IsRoot) {
                numRoots++;
                getChildrenAsync(nodes[i], nodes, create);
            }
        }
        function create(child){
            roots.push(child);
            if(roots.length === numRoots){
                var trees = "";
                for (var j = 0; j < roots.length; j++) {
                    trees += "<div class='sitemapRoot'><ul><li>" + roots[j].html + "</li></ul></div>";
                }
                callback(trees);
            }
        }   
    }
    function getChildrenAsync(root, nodes, callback) {
        var result = "";
        var index = 0;
        var children = [];
        for (var i = 0; i < nodes.length; i++) {
            if (nodes[i].Parent == root.Child) {
                index += 1;
                getChild(i);
            }
        }
    
        if (index == 0) {
            root.html = root.Child;
            callback(root);
        }
        function getChild(x){
            setTimeout(function(){
                getChildrenAsync(nodes[x], nodes, createHtml);
            });
        }
        function createHtml(node){
            children.push(node);
            if(children.length === index){      
                var result = root.Child;
                if(children.length){
                    result += "<ul>"
                    for (var j = 0; j < children.length; j++) {
                        result += "<li>" + children[j].html + "</li>";
                    }
                    result += "</ul>";
                }
                root.html = result;
                callback(root);
            }
        }
    }
    

    您是否检查了数据中的循环引用?哪一行出现此错误?@MuratGündeşfunction getChildren(root,nodes)@LS_dev是的,这是不可能的。子节点不能将父节点包含为子节点。您是否检查了数据中的循环引用?出现此错误的是哪一行?@MuratGündeşfunction getChildren(root,nodes)@LS_dev是的,这是不可能的。子节点不能将父节点包含为子节点。您能详细解释一下,当有更大的调用堆栈时,为什么我们需要使函数异步吗?有更多信息的资源吗?@Hylle如果调用堆栈太大,您应该使函数异步,或者有办法退出递归调用,以免导致堆栈溢出错误。递归方法每次调用时都会将新方法放入堆栈中,因此如果不小心,最终可能会溢出堆栈。Async可能会减轻错误,但如果方法本身需要重构并且操作过于繁重,则可能会导致应用程序速度非常慢。关于调用堆栈和递归javascript调用,有一些参考资料……您能否解释一下,当调用堆栈较大时,为什么我们需要使函数异步?有更多信息的资源吗?@Hylle如果调用堆栈太大,您应该使函数异步,或者有办法退出递归调用,以免导致堆栈溢出错误。递归方法每次调用时都会将新方法放入堆栈中,因此如果不小心,最终可能会溢出堆栈。Async可能会减轻错误,但如果方法本身需要重构并且操作过于繁重,则可能会导致应用程序速度非常慢。关于调用堆栈和递归javascript调用,有一些参考资料。。。
    var body = $("body");
    body.append(makeTree(makeTestNodes(20, 50)));
    
    makeTreeAsync(makeTestNodes(20, 50), function(html){
        body.append(html);
    });