有人可以给出一个清晰的定义,以及一个简单的示例,为不了解JavaScript和node.js的人解释什么是“回调地狱”吗?
什么时候(以哪种设置)发生“回调地狱问题”?
为什么会发生?
“回调地狱”是否总是与异步计算相关?
还是在单线程应用程序中也可能发生“回调地狱”?
我在Coursera参加了“反应式课程”,Erik Meijer在他的一次演讲中说RX解决了“回调地狱”的问题。我在Coursera论坛上问什么是“回调地狱”,但我没有明确的答案。
在一个简单的示例上解释了“回调地狱”之后,您还可以说明该简单示例上的RX如何解决“回调地狱问题”吗?
Javascript中的问题在于,“冻结”计算并使“其余部分”(异步地)执行的唯一方法是将“其余部分”放入回调中。
例如,假设我要运行如下代码:
x = getData(); y = getMoreData(x); z = getMoreData(y); ...
如果现在我想使getData函数异步,这意味着我有机会在等待其他代码返回值时运行一些其他代码,会发生什么情况?在Javascript中,唯一的方法是使用延续传递样式重写所有与异步计算有关的内容:
getData(function(x){ getMoreData(x, function(y){ getMoreData(y, function(z){ ... }); }); });
我认为我不需要说服任何人此版本比以前的版本丑陋。:-)
当您的代码中有很多回调函数时!与您的代码一起使用的人越多,与他们的合作就越困难,而当您需要执行循环,try-catch块之类的事情时,情况就变得尤其糟糕。
例如,据我所知,在JavaScript中执行一系列异步函数的唯一方法是使用递归函数,该异步函数在先前的返回之后运行。您不能使用for循环。
// we would like to write the following for(var i=0; i<10; i++){ doSomething(i); } blah();
相反,我们可能需要结束编写:
function loop(i, onDone){ if(i >= 10){ onDone() }else{ doSomething(i, function(){ loop(i+1, onDone); }); } } loop(0, function(){ blah(); }); //ugh!
我们在StackOverflow上收到的许多问题询问如何做这种事情,这证明了它是多么令人困惑:)
发生这种情况的原因是,在JavaScript中,延迟计算以使其在异步调用返回之后运行的唯一方法是将延迟的代码放入回调函数中。您不能延迟以传统同步样式编写的代码,因此最终到处都有嵌套的回调。
异步编程与并发有关,而单线程与并行性有关。这两个概念实际上不是一回事。
您仍然可以在单个线程上下文中拥有并发代码。实际上,JavaScript是回调地狱的女王,是单线程的。
我对RX一点都不了解,但是通常可以通过在编程语言中添加对异步计算的本机支持来解决此问题。实现可能有所不同,包括:异步,生成器,协程和callcc。
在Python中,我们可以使用类似于以下内容的代码来实现该先前的循环示例:
def myLoop(): for i in range(10): doSomething(i) yield myGen = myLoop()
这不是完整的代码,但是其思想是“yield”暂停我们的for循环,直到有人调用myGen.next()。重要的是,我们仍然可以使用for循环来编写代码,而无需像在递归loop函数中那样将逻辑“由内而外” 。
loop