在javascript中链接asynchronous调用的正确方法是什么?

我试图find最好的方式来创buildasynchronous调用时,每个电话取决于先前的电话已完成。 目前我通过recursion调用定义的过程函数来链接方法,如下所示。

这是我目前正在做的。

var syncProduct = (function() { var done, log; var IN_CAT = 1, IN_TITLES = 2, IN_BINS = 3; var state = IN_CAT; var processNext = function(data) { switch(state) { case IN_CAT: SVC.sendJsonRequest(url("/api/lineplan/categories"), processNext); state = IN_TITLES; break; case IN_TITLES: log((data ? data.length : "No") + " categories retrieved!"); SVC.sendJsonRequest(url("/api/lineplan/titles"), processNext); state = IN_BINS; break; case IN_BINS: log((data ? data.length : "No") + " titles retrieved!"); SVC.sendJsonRequest(url("/api/lineplan/bins"), processNext); state = IN_MAJOR; break; default: log((data ? data.length : "No") + " bins retrieved!"); done(); break; } } return { start: function(doneCB, logCB) { done = doneCB; log = logCB; state = IN_CAT; processNext(); } } })(); 

然后,我会这样称呼如下

 var log = function(message) { // Impl removed. } syncProduct.start(function() { log("Product Sync Complete!"); }, log); 

虽然这对我来说工作得很好,但我不禁想到要有一个更好(更简单)的方法。 当我的recursion调用太深时,会发生什么?

注意 :我没有在浏览器中使用JavaScript,而是在Titanium框架中使用JavaScript,这与Node.js的Javascript类似。

有很多库和工具可以为你做asynchronous链接和控制stream程,主要有两种:

  1. 控制stream库

    例如,请参阅asynchronous , 序列和步骤 (基于callback)或Q和期货 (基于承诺)。 这些的主要优点是,他们只是平原JS库,缓解asynchronous编程的痛苦。

    以我个人的经验,基于承诺的库往往会导致代码看起来更像通常的同步代码,因为您使用“return”返回值,因为承诺值可以传递和存储在周围,类似于实际值。

    另一方面,基于延续的代码是更低层次的,因为它明确地操纵代码path。 这可能会允许更灵活的控制stream程,并更好地与现有的库集成,但也可能导致更多的样式和不太直观的代码。

  2. Javascript的CPS编译器

    扩展语言以增加对协同程序/生成器的本地支持可让您以非常直接的方式编写asynchronous代码,并且与其他语言相得益彰,这意味着您可以使用Javascript if语句,循环等而不需要使用函数复制它们。 这也意味着它很容易将以前的同步代码转换为asynchronous版本。 然而,有一个明显的缺点,就是不是所有的浏览器都会运行你的Javascript扩展,所以你需要在你的构build过程中添加一个编译步骤,将你的代码转换为正常的JS,并使用延续传递风格的callback。 无论如何,一个有希望的替代scheme是Ecmascript 6规范中的生成器 – 虽然firefox现在只支持它们,但还有一些项目,比如再生器和Traceur将它们编译回callback。 还有其他项目可以创build自己的asynchronous语法(因为es6生成器还没有出现)。 在这一类,你会发现诸如tamejs和冰咖啡的东西 。 最后,如果你使用Node.js,你也可以看看Fibers 。


我的推荐:

如果你只是想要一些简单的,不会使你的构build过程复杂化的东西,那么我会build议使用最适合你的个人风格和你已经使用的库的控制stream库。

但是,如果您希望编写大量复杂且深度集成的asynchronous代码,我强烈build议您至less考虑一下基于编译器的替代方法。