Javascript 如何避免;超过最大调用堆栈大小;例外?
我有下一个代码生成网站地图树的URL列表。 C#模型: 生成节点列表的C#方法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 =
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;i因此,问题是如何优化代码以避免此错误?有两种方法可以解决此问题。在使用递归函数时,您总是需要担心调用堆栈的大小。如果您认为这是一个问题,那么您需要进行异步或重构以避免递归。这些不一定是最优化的答案,但希望它们能让你开始 非递归函数
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);
});