如果回调调用封闭函数,它是否被称为递归调用
If a callback calls the enclosing function, would it be called a recursive call?
例如:
如果http.request
调用是在res.on('end')
回调中进行的,那么调用是递归的吗?
http.request(options, function(res) {
res.on('data', function(chunk) {
data+=chunk;
});
res.on('end', function(){
//do some stuff
http.request(options, function(res) {...});//is this recursive?
});
}).end();
编辑:
让我们举一个更简单的例子:假设有一个函数逐个字符读取文件:
var noOfChar = 10;
var i = 0;
readChar(function processChar(char){
if(i < noOfChar) {
console.log(char);
i++;
readChar(processChar); //is this recursive?
}
}
与其争论要标记什么,不如让我们考虑一下代码的一些具体属性,以及它与人们通常所说的"递归"有何相似或不同。
通常,递归函数是在每一步都增加堆栈的东西(尾部调用递归除外,它使用了一个技巧来防止这种增长)。但在 node 中,异步回调会丢弃外部上下文的堆栈。(尝试在回调中引发异常,然后自己看看。因此,此代码不会增加堆栈。
通常递归函数是调用自己的函数,但我在您的示例中没有看到这种情况发生。http
上的两个侦听器是不同的功能。
第二个示例不直接调用自己,但它确实间接调用自己。你有一个"基本情况"(noOfChar >= 10
),此时递归展开。如果readChar
同步的,您甚至会增加堆栈。所以这似乎更接近递归。
请注意,在第二个示例中,您有一个命名函数,而第一个示例只有匿名函数。一般来说,我认为如果没有命名函数(或至少是一些保存函数的变量)就不可能递归,因为否则函数如何引用自身?
如果您要向它传递不同的callback
,我认为它不会是递归的。
如果您将相同的callback
传递给两者,它将是递归的。
递归意味着如果我在函数定义本身中调用相同的函数。但是,如果您要传递不同的回调,它将类似于波纹管。
假设您有 2 个不同的回调callback1 and callback2
。
您已将第一个回调传递给外部http.request
,将第二个回调传递给内部http.request
,因此外部http.request
将执行callback1
中给出的代码,但内部将执行callback2
中给出的代码。
我不明白这个问题的含义。
如果答案是肯定的,你会被老板鞭打致死吗?
有没有反对递归的法律?
http.request
只是达到目的的手段。无论如何,您需要多次调用它来处理事务。
示例代码的问题在于,您在一大块代码中处理异步交换,该代码直接处理响应而不跟踪事务的状态。
我想到的唯一评论是,这种逻辑非常脆弱,因为终止条件取决于传递给您的请求的任何参数,从而为一系列潜在问题敞开了大门,例如不同步的答案和无限循环(如果它们最终挂起系统,它们是否值得"递归调用"的名称就没什么意义了)。
我宁愿建议构建一个显式状态机来跟踪预期的HTTP交换的进度,这将免除有关递归性和相关"良好实践"的哲学问题。
尝试回答我自己的问题,因为我认为现在我对递归的理解更好了。也许这会帮助其他人。
我的怀疑是,如果一个函数调用一个回调,再次调用该函数,它会被称为递归。我觉得这类似于间接递归,其中函数 1 调用函数 2,函数 2 再次调用函数 1。因此,如果函数 1 调用函数 2 而函数 3 又调用函数 1 并不重要,它仍然是递归的。同样,函数调用一个回调,调用另一个调用函数的回调也无关紧要。如果第二个示例是递归的,则第一个示例也可以是递归的。
问题的递归解决方案必须更多地与问题的解决方式有关,而不是像堆栈增长这样的语言实现。考虑tail-recursion
,它不会增加调用堆栈,但没有人质疑它的递归性。
所以关键点是递归思考。以整个问题为例,如果其中一部分可以用与原始问题相同的方式解决,那么解决方案就是递归的。调用自身的函数可能不符合递归的条件。有些人可能称其为自引用函数,但不是递归函数。
递归至少应该由一个基本情况和一个递归情况组成,每个自引用都应该使输入值更接近基本情况,这将结束递归。所以我认为问题中提到的两个例子都不是递归的。
递归调用可能不会导致调用堆栈增加。有尾部调用递归,它保持调用堆栈大小恒定。
以以下由回调组成的示例为例,此处外部函数堆栈帧可能在内存中,也可能不在内存中。
var input = [[1,2,3],[4,5,6],[7,8,9]];
function double(ip) {
return ip.map(function (element) {
if(Array.isArray(element)) {
return double(element);
}
else {
return 2 * element;
}
});
}
console.log(double(input));
我会称之为递归。我们也可以做匿名递归,所以显式命名函数是不必要的。
- 同步(阻塞)ajax调用是否可以阻塞浏览器'的UI
- 如果我返回表,检查 Ajax 调用是否为 200 OK的最佳方法是什么
- 异步函数调用是否可以在两个同步语句之间完成
- 并行或串行编写多个 AJAX 调用是否更好
- XMLhttpRequest 的问题,不确定调用是否正确
- 确定 .always 函数中的 AJAX 调用是否失败
- 检测所有 XMLHttpRequest 调用是否已完成
- 检查函数调用是否具有正确的参数类型
- 如果没有jQuery,javascript如何检查多个ajax调用是否已经完成,一旦完成,就执行一段代码
- 检查构造函数调用是否来自扩展类
- AJAX调用是否有返回HTML内容和回调函数的方法
- requestAnimationFrame调用是否总是被抑制到60 FPS.只要屏幕准备重新绘制,就会调用
- 如何检查函数调用是否有参数
- 如何判断$(".").each()调用是否过早中止?
- 如何检测调用是否通过jQuery进行
- 如何检查ajax .load调用是否已加载
- $scope.$apply()调用是否适用于此场景?
- 检查函数调用是否为变量定义
- 检查ajax调用是否完成
- 如何检查ajax调用是否已完成以及何时完成