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