Node.js的异步调用和递归 [英] Asynchronous Calls and Recursion with Node.js

查看:104
本文介绍了Node.js的异步调用和递归的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望在完全完成递归函数后执行回调,该递归函数可以持续一段不确定的时间。我正在努力解决异步问题,希望能在这里得到一些帮助。使用请求模块的代码如下:

  var start = function(回调){
request.get({
url:'aaa.com'
},函数(错误,响应,正文){
var startingPlace = JSON .parse(body).id;
recurse(startingPlace,callback);
});
};

var recurse = function(startingPlace,callback){
request.get({
url:'bbb'
},函数(错误,响应,正文) {
//在这些功能之外的某处存储主体
//发出第二个请求
request.get({
url:'ccc'
},函数(错误,响应,正文){
var anArray = JSON.parse(body).stuff;
if(anArray){
anArray.forEach(function(thing){
request.get ({
url:'ddd'
},函数(错误,响应,正文){
var nextPlace = JSON.parse(body).place;
recurse(nextPlace) ;
});
})
}
});
});
callback();
};

start(函数(){
//调用最终函数打印出每次递归调用时更新的存储结果
finalFunction();
});

一旦我的代码超过 在嵌套请求中循环,它继续执行请求并在递归调用仍在进行时结束初始函数调用。我希望它不会完成最高级别的迭代,直到所有嵌套的递归调用完成(我无法知道有多少)。



任何帮助非常感谢!

解决方案

在您的示例中,您没有递归调用。如果我理解正确你想说 recurse(point,otherFunc); 是递归调用的开始。



<然后回到递归调用的定义(你没有在帖子中显示)并执行此操作(为递归结束时调用的回调函数添加第三个参数;调用者将其传递为参数):

 函数recurse(startingPlace,otherFunc,callback_one){
//您可能拥有的代码.. 。
if(your_terminating_criterion === true){
return callback_one(val); //其中val可能是你要返回的某个值(或者带有结果的json对象)
}
//你可能有更多代码
}

然后在您发布的原始代码中,改为进行此调用(在最内部):

  recurse(startingPlace,otherFunc,function(results){
//结果现在是一个变量,在递归结束时返回数据
console.log(Recursion finished with results+ results);
callback(); //你想从头开始调用的回调
});

花一些时间尝试理解我的解释。当你明白,那么你就会知道节点。这是一篇文章中的节点哲学。我希望很清楚。您的第一个示例应如下所示:

  var start = function(callback){
request.get({
url:'aaa.com'
},函数(错误,响应,正文){
var startingPlace = JSON.parse(body).id;
recurse(startingPlace, otherFunc,function(results){
console.log(Recursion finished with results+ results);
callback();
});
});
};

以下是您感兴趣的其他信息。否则,您将使用上述设置。



通常在node.js中,人们也会返回错误值,以便调用者知道函数是否正常被调用已成功完成。这里没有什么大不了的。人们不会只返回结果而是拨打表格

 返回callback_one(null,val); 

然后在另一个功能中你可以拥有:

  recurse(startingPlace,otherFunc,function(recError,results){
if(recErr){
//处理来自递归的错误
return callback(); // important:使用return,否则当回调结束时你将继续执行if部分之后的任何内容;)
}

//没有问题/错误
console.log(递归完成结果+结果);
callback(); //写下`return callback();`当你想在那里停止执行并实际调用callback()
})时,`这不是一个坏习惯;

根据我的建议更新



这是我对递归函数的建议,但在此之前,看起来你需要定义自己的 get

  function myGet(a,callback){
request.get(a,function(error,response,body){
var nextPlace = JSON.parse(body).place;
返回回调(null,nextPlace); // null表示没有错误,并将nextPlace返回async
});
}

var recurse = function(startingPlace,callback2){
request.get({
url:'bbb'
},function(error1) ,response1,body1){
//在这些功能之外的某处存储主体
//发出第二个请求
request.get({
url:'ccc'
} ,function(error2,response2,body2){
var anArray = JSON.parse(body2).stuff;
if(anArray){
//你要为每个人调用的函数数组的元素是`get`。
//所以,准备这些调用,但你还需要传递不同的参数
//这就是`bind`进入图片和链接我早先给了。
var theParallelCalls = [];
for(var i = 0; i< anArray.length; i ++){
theParallelCalls.push(myGet.bind(null,{ url:'ddd'})); //这里,在执行期间,paral lel将传递自己的回调作为`myGet`的第三个参数;这就是为什么我们在代码中有回调和callback2
}
//现在执行并行调用:
async.parallel(theParallelCalls,function(error3,results){
/ /所有并行调用都返回
for(var i = 0; i< results.length; i ++){
var nextPlace = results [i];
recurse(nextPlace,callback2) ;
}
});
} else {
return callback2(null);
}
});
});
};

请注意,我假设获取请求对于'bbb',后面跟着'ccc'的 get 请求。换句话说,你没有为你有评论的递归调用隐藏一个返回点。


I'm looking to execute a callback upon the full completion of a recursive function that can go on for an undetermined amount of time. I'm struggling with async issues and was hoping to get some help here. The code, using the request module, is as follows:

var start = function(callback) {
  request.get({
    url: 'aaa.com'
  }, function (error, response, body) {
    var startingPlace = JSON.parse(body).id;
    recurse(startingPlace, callback);
  });
};

var recurse = function(startingPlace, callback) {
    request.get({
        url: 'bbb'
    }, function(error, response, body) {
        // store body somewhere outside these funtions
        // make second request
        request.get({
            url: 'ccc'
        }, function(error, response, body) {
            var anArray = JSON.parse(body).stuff;
            if (anArray) {
                anArray.forEach(function(thing) {
                    request.get({
                        url: 'ddd'
                    }, function(error, response, body) {
                        var nextPlace = JSON.parse(body).place;
                        recurse(nextPlace);
                    });
                })
            }
        });
    });
    callback();
};

start(function() {
    // calls final function to print out results from storage that gets updated each     recursive call
    finalFunction();
});

It seems that once my code goes past the for loop in the nested requests, it continues out of the request and ends the initial function call while the recursive calls are still going on. I want it to not finish the highest-level iteration until all the nested recursive calls have completed (which I have no way of knowing how many there are).

Any help is GREATLY appreciated!

解决方案

In your example you have no recursive calls. If I understand correctly you want to say that recurse(point, otherFunc); is the beginning of a recursive call.

Then just go back to the definition of the recursive call (which you have not shown in your post) and do this (add a third argument for a callback function to be called in the end of recursion; the caller will pass it as a parameter):

function recurse(startingPlace, otherFunc, callback_one) {
    // code you may have ...
    if (your_terminating_criterion === true) {
         return callback_one(val); // where val is potentially some value you want to return (or a json object with results)
    }
    // more code you may have
}

Then in the original code that you posted, make this call instead (in the inner-most part):

recurse(startingPlace, otherFunc, function (results) {
    // results is now a variable with the data returned at the end of recursion
    console.log ("Recursion finished with results " + results);
    callback();   // the callback that you wanted to call right from the beginning
});

Just spend some time and try to understand my explanation. When you understand, then you will know node. This is the node philosophy in one post. I hope it is clear. Your very first example should look like this:

var start = function(callback) {
  request.get({
    url: 'aaa.com'
  }, function (error, response, body) {
    var startingPlace = JSON.parse(body).id;
    recurse(startingPlace, otherFunc, function (results) {
        console.log ("Recursion finished with results " + results);
        callback();
    });
  });
};

Below is only additional information in case you are interested. Otherwise you are set with the above.

Typically in node.js though, people return an error value as well, so that the caller knows if the function that was called has finished successfully. There is no big mystery here. Instead of returning just results people make a call of the form

return callback_one(null, val);

Then in the other function you can have:

recurse(startingPlace, otherFunc, function (recError, results) {
    if (recErr) {
         // treat the error from recursion
         return callback(); // important: use return, otherwise you will keep on executing whatever is there after the if part when the callback ends ;)
    }

    // No problems/errors
    console.log ("Recursion finished with results " + results);
    callback();   // writing down `return callback();` is not a bad habit when you want to stop execution there and actually call the callback()
});

Update with my suggestion

This is my suggestion for the recursive function, but before that, it looks like you need to define your own get:

function myGet (a, callback) {
    request.get(a, function (error, response, body) {
        var nextPlace = JSON.parse(body).place;
        return callback(null, nextPlace); // null for no errors, and return the nextPlace to async
    });
}

var recurse = function(startingPlace, callback2) {
    request.get({
        url: 'bbb'
    }, function(error1, response1, body1) {
        // store body somewhere outside these funtions
        // make second request
        request.get({
            url: 'ccc'
        }, function(error2, response2, body2) {
            var anArray = JSON.parse(body2).stuff;
            if (anArray) {
                // The function that you want to call for each element of the array is `get`.
                // So, prepare these calls, but you also need to pass different arguments
                // and this is where `bind` comes into the picture and the link that I gave earlier.
                var theParallelCalls = [];
                for (var i = 0; i < anArray.length; i++) {
                    theParallelCalls.push(myGet.bind(null, {url: 'ddd'})); // Here, during the execution, parallel will pass its own callback as third argument of `myGet`; this is why we have callback and callback2 in the code
                }
                // Now perform the parallel calls:
                async.parallel(theParallelCalls, function (error3, results) {
                    // All the parallel calls have returned
                    for (var i = 0; i < results.length; i++) {
                        var nextPlace = results[i];
                        recurse(nextPlace, callback2);
                    }
                });
            } else {
                return callback2(null);
            }
        });
    });
};

Note that I assume that the get request for 'bbb' is always followed by a get request for 'ccc'. In other words, you have not hidden a return point for the recursive calls where you have the comments.

这篇关于Node.js的异步调用和递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆