使用setTimeout()进行Javascript回调地狱

时间:2012-09-26 00:47:21

标签: javascript callback settimeout

阿罗哈。这是我潜伏之后的第一个问题。我为这个问题的详细但直接的形式道歉 - 以及对可接受的答案的限制 - 但我在这里做出贡献。我有一个问题,其他问题(例如How to avoid long nesting of asynchronous functions in Node.jsChained callback readability in Javascript?)并不能让我满意。

我想执行几个Javascript回调,以便我有一个接一个发生的四个动作的序列。这是来源:

var self = this;
fade(div, fadeIn, -20, function() {
  load(unload, dataOut, -10, function() {
    load(self, dataIn, 10, function() {
      fade(div, fadeOut, 20),0);
      unload = self;}
    );}
  );}
);

除了内部语义细节之外,load()和fade()函数非常相似,它们看起来与此类似:

function load(menuCategory, data, step, callback) {
  menuCategory.parentNode.style.width = data+"px";
  data += step;
  if(dataIn <= data && data <= dataOut) {
    setTimeout(function() { load(menuCategory,data,step,callback) }, 15);
  } else if(callback && (typeof(callback) == 'function')) { 
    callback();}
}

我有几个问题与这个混乱有关,但首先让我给你我不寻找的答案。使用jQuery的答案是不可接受的。使用其他计时或“同步”框架或模块的答案是不可接受的。质疑阻止执行的原因的答案是不可接受的。使用Javascript以外的语言的答案是不可接受的。非抽象答案是可以接受的,但最终解决方案需要尽可能抽象,这意味着答案必须能够对各种相似但略有不同的行为采取行动。

这是我的主要问题: 是否有一个函数/对象我可以用来顺序地应用这些动作,以减少在这里发生的回调?换句话说,如果对象/函数能够同步执行每个动作,因为它是单独迭代通过它(即传递给它),对象会是什么样子?

次要问题: 是否有人知道这个回调业务在其他语言中看起来像goto()多少?意思是,这种回调嵌套对我来说感觉非常尴尬和不优雅。是否有开发或已经开发的Javascript语言构造可以减少这种疯狂的业务?回调嵌套是一个最难遵循的逻辑流程。这感觉很尴尬。

我的目标是一个紧凑,优雅,有吸引力的本土Javascript对象/函数 - 我可以在for()循环或等效函数中调用 - 按顺序对每个动作应用这些操作。如果您已经读过这篇文章,我想感谢您的时间和考虑。 :)

3 个答案:

答案 0 :(得分:6)

  

使用setTimeout(func(),0)以便同步执行

没有。使用func()进行同步执行,或setTimeout(func, 0)对执行进行排队(使其异步)。

  

setTimeout(func[…],0)是将此操作放入渲染网页对象的执行队列的“最优雅”方式吗?换句话说,是否有一种“更优雅”的方式来阻止执行(即按顺序执行这些操作)?

是的,这是标准方法。但是,这样做块执行,并且与排序无关。如果执行是同步的,只需执行它,否则你将不得不处理回调并排队新任务 not help。

  

有人知道这个回调业务在其他语言中看起来像goto()多少?意思是,这种回调嵌套对我来说感觉非常尴尬和不优雅。是否有开发或已经开发的Javascript语言结构可以减少这种疯狂的业务?

不,我不知道其他语言,但是afaik goto是一个同步的控制流结构语句,因为它不处理异步操作。

但不,没有JavaScript语言结构(“语法糖”)可以帮助我们绕过continuation-passing style回调地狱。

  

我是否可以使用一个函数/对象来顺序应用这些操作,以减少这里的回调?换句话说,如果对象/函数能够同步执行每个动作,因为它是单独迭代通过它(即传递给它),对象会是什么样子?

     

我的目标是一个紧凑,优雅,有吸引力的本土Javascript对象/函数 - 我可以在for()循环或等效函数中调用 - 按顺序对每个动作应用这些操作。

再次,您想要“顺序”而不是“同步”:-)是的,有[手动编码/自行开发]解决方案,可以更轻松地处理回调。正如您提到的those callback organisation libraries不满足您,我建议您查看非常优雅且有吸引力的Promise Api及其延迟对象(请参阅futures and promises了解此概念)。

答案 1 :(得分:2)

我不确定你为什么要在这里使用setTimeout。没有必要排队回调。假设fade()和load()正确处理回调执行,以下结构将起作用。

fade(div, fadeIn, -20, function() {
    load(unload, dataOut, -10, function() {
        load(self, dataIn, 10, function() {
            fade(div, fadeOut, 20),0);
        });
    )};
)};

你应该研究的另一个话题是Promises,也称为延期和期货。它本质上是一种专门处理嵌套回调的编码模式。在root上,您创建一个立即返回的Promise对象,然后当您的方法执行完毕后,它会在promise上触发一个方法,然后可以执行您的下一个函数。它是一种不同的编写javascript的方式,但易于理解且非常有用。

答案 2 :(得分:1)

事实证明,适合我问题的“最佳”答案的做法是事件。特别是我所指的实践最好由Node.js上的EventEmitter描述,或者在客户端浏览器上创建自定义事件和事件监听器。虽然Promise API及其deference模型很有趣,但它使用了语言的扩展而不是核心Javascript,这是我在这里特别寻找的(因此为什么以前的答案都没有 - 尽管它们清晰 - 完全支持我在寻找什么。)

此链接(http://wekeroad.com/2012/04/05/cleaning-up-deep-callback-nesting-with-nodes-eventemitter)提供了我正在寻找的非常好的示例。同样,我应该提到Trevor Burnham的书“Async Javascript”(http://www.amazon.com/Async-JavaScript-Trevor-Burnham/dp/1475247362),以及John Resig和Bear Bibeault(http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X)的“JavaScript Ninja的秘密”。这些书籍提供了非常清晰的客户端浏览器中自定义事件和事件处理程序的工作示例,它们提供了一种优雅的方式来解决我所指的“回调地狱”。