asynchronous调用和Node.jsrecursion

我正在寻找一个完整的recursion函数,可以继续一个不确定的时间执行callback。 我正在努力解决asynchronous问题,希望能在这里得到一些帮助。 使用request模块的代码如下所示:

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

看起来,一旦我的代码在嵌套请求中经过for循环,它就会继续执行请求,并在recursion调用仍在继续时结束初始函数调用。 我希望它不能完成最高级别的迭代,直到所有的嵌套recursion调用完成(我无法知道有多less)。

任何帮助是极大的赞赏!

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

然后回到recursion调用(你没有在你的post中显示)的定义,并做到这一点(添加第三个参数,在recursion结束时调用一个callback函数;调用者将它作为parameter passing):

 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 } 

然后在您发布的原始代码中,改为调用此代码(在最里面的部分):

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

花点时间,试着理解我的解释。 当你明白的时候,你就会知道节点。 这是一篇文章中的节点哲学。 我希望很清楚。 你的第一个例子应该是这样的:

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

如果您有兴趣,以下只是附加信息。 否则,您将被设置为上述。

通常在node.js中,人们也返回一个错误值,以便调用者知道被调用的函数是否成功完成。 这里没有什么大的谜团。 人们不只是返回results而是呼叫表单

 return callback_one(null, val); 

然后在另一个函数中可以有:

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

更新我的build议

这是我对recursion函数的build议,但在此之前,它看起来像你需要定义自己的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); } }); }); }; 

请注意,我假设“bbb”的get请求后面总是跟着“ccc”的get请求。 换句话说,在你有注释的时候,你还没有隐藏recursion调用的返回点。

通常当你写一个recursion函数时,它会做一些事情 ,然后自己调用或返回。

您需要在recursion函数的范围(即recurse而不是start )中定义callback ,并且您需要在通常返回的位置调用它。

所以,一个假设的例子看起来像这样:

 get_all_pages(callback, page) { page = page || 1; request.get({ url: "http://example.com/getPage.php", data: { page_number: 1 }, success: function (data) { if (data.is_last_page) { // We are at the end so we call the callback callback(page); } else { // We are not at the end so we recurse get_all_pages(callback, page + 1); } } } } function show_page_count(data) { alert(data); } get_all_pages(show_page_count); 

我想你可能会发现caolan / async有用。 特别async.waterfall 。 它将允许您从另一个callback中传递结果,完成后,对结果进行一些操作。

例:

 async.waterfall([ function(cb) { request.get({ url: 'aaa.com' }, function(err, res, body) { if(err) { return cb(err); } cb(null, JSON.parse(body).id); }); }, function(id, cb) { // do that otherFunc now // ... cb(); // remember to pass result here } ], function (err, result) { // do something with possible error and result now }); 

如果recursion函数是同步的,只需在下一行调用callback函数:

 var start = function(callback) { request.get({ url: 'aaa.com' }, function (error, response, body) { var startingPlace = JSON.parse(body).id; recurse(startingPlace, otherFunc); // Call output function AFTER recursion has completed callback(); }); }; 

否则,您需要在recursion函数中保留对callback的引用。

将callback作为parameter passing给函数,并在完成时调用它。

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

从这个例子构build你的代码:

 var udpate = function (callback){ //Do stuff callback(null); } function doUpdate() { update(updateDone) } function updateDone(err) { if (err) throw err; else doUpdate() } doUpdate();