javascript - Node.js 的异步调用和递归

标签 javascript node.js asynchronous recursion

我希望在递归函数完全完成时执行回调,该函数可以持续不确定的时间量。我正在为异步问题而苦苦挣扎,希望能在这里得到一些帮助。使用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 循环,它就会继续执行请求并结束初始函数调用,而递归调用仍在继续。我希望它在所有嵌套递归调用完成之前不完成最高级别的迭代(我无法知道有多少)。

非常感谢任何帮助!

最佳答案

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

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

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

只需花一些时间并尝试理解我的解释。当你理解了,你就会知道 Node 。这是一篇文章中的 Node 哲学。我希望它是清楚的。您的第一个示例应如下所示:

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 中,人们也会返回一个错误值,以便调用者知道被调用的函数是否已成功完成。这里没有什么大的奥秘。人们不是只返回结果,而是调用表单

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

根据我的建议更新

这是我对递归函数的建议,但在此之前,您似乎需要定义自己的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 请求之后。换句话说,您没有在有评论的地方隐藏递归调用的返回点。

关于javascript - Node.js 的异步调用和递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26515671/

相关文章:

python - 在 Tornado 中,如何查看在 PeriodicCallback 调用的协程中引发的异常?

objective-c - 如何在 objective-c 中编写非阻塞方法

php - 无法使用 javascript 打印 AJAX 返回的数组

c# - 在 jquery 中启用可排序

javascript - Response.write() 不返回值

mysql - Sails 不会填充大型查询

node.js - JSON.stringify() 未正确将对象转换为字符串

javascript - javascript 中的 await 关键字会降低应用程序的速度吗?

javascript - React-chartjs-2 圆环图导出为png

javascript - link_一键指向多个链接