我正在尝试找到创建异步调用的最佳方法,因为每次调用都取决于先前的调用已完成。目前,我正在通过递归调用已定义的流程函数来链接方法,如下所示。
这就是我目前正在做的事情。
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);
虽然这对我来说非常好,但我不禁想到必须有更好(更简单)的方法。以后当我的递归调用变得太深时会发生什么?
注意:我不是在浏览器中使用javascript,而是在Titanium框架中使用javascript,这类似于Node.js的Javascript。
答案 0 :(得分:26)
有许多库和工具可以为您执行异步链接和控制流程,它们主要有两种主要类型:
控制流程库
例如,请参阅async,seq和step(基于回调)或Q和futures(基于承诺)。这些的主要优点是它们只是平原JS库,可以减轻异步编程的痛苦。
根据我的个人经验,基于承诺的库往往会导致代码看起来更像通常的同步代码,因为您使用“return”返回值,因为promise值可以传递和存储,类似于实际值。 / p>
另一方面,基于延续的代码更低级别,因为它明确地操作代码路径。这可能允许更灵活的控制流程以及与现有库的更好集成,但它也可能导致更多的样板和更不直观的代码。
Javascript CPS编译器
扩展语言以添加协同程序/生成器的本机支持允许您以非常简单的方式编写异步代码并与其他语言一起使用,这意味着您可以使用Javascript if语句,循环等而不需要使用它来复制它们功能。这也意味着它很容易将以前的同步代码转换为异步版本。但是,显而易见的缺点是并非每个浏览器都会运行您的Javascript扩展,因此您需要在构建过程中添加一个编译步骤,以便将您的代码转换为具有continuation-passing-style回调的常规JS。无论如何,一个有前途的替代方案是Ecmascript 6规范中的生成器 - 虽然现在只有firefox本身支持它们,但是有regenerator和Traceur等项目将它们编译回回调。还有其他项目创建自己的异步语法(因为es6生成器当时没有出现)。在此类别中,您会找到tamejs和Iced Coffeescript等内容。最后,如果您使用Node.js,您还可以查看Fibers。
我的推荐:
如果你只是想要一些不会使你的构建过程复杂化的简单东西,我会建议你选择最适合你个人风格的控制流库和你已经使用过的库。
但是,如果您希望编写大量复杂且深度集成的异步代码,我强烈建议您至少查看基于编译器的替代代码。