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

Bre*_*yan 16 javascript titanium serverside-javascript node.js titanium-mobile

我正在尝试找到创建异步调用的最佳方法,当每个调用依赖于先前的调用已完成.目前我通过递归调用定义的过程函数来链接方法,如下所示.

这就是我目前正在做的事情.

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();
        }
    }
})();
Run Code Online (Sandbox Code Playgroud)

我会这样称呼如下

var log = function(message) {
    // Impl removed.
}

syncProduct.start(function() {
    log("Product Sync Complete!");
}, log);
Run Code Online (Sandbox Code Playgroud)

虽然这对我来说非常好,但我不得不认为必须有更好(更简单)的方法.以后当我的递归调用变得太深时会发生什么?

注意:我没有在浏览器中使用javascript,而是在Titanium框架内本地使用,这类似于Node.js的Javascript.

hug*_*omg 26

有许多库和工具可以为您执行异步链接和控制流程,它们主要有两种主要类型:

  1. 控制流库

    例如,请参阅async,seqstep(基于回调)或Q期货(基于承诺).这些的主要优点是它们只是平原JS库,可以减轻异步编程的痛苦.

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

    另一方面,基于延续的代码是更低级别的,因为它明确地操纵代码路径.这可能允许更灵活的控制流和更好地与现有库集成,但它也可能导致更多的样板和更不直观的代码.

  2. Javascript CPS编译器

    扩展语言以添加对协同程序/生成器的本机支持使您可以以非常简单的方式编写异步代码,并且与其他语言一起使用很好,这意味着您可以使用Javascript if语句,循环等而不需要使用函数复制它们.这也意味着它很容易将以前的同步代码转换为异步版本.但是,显而易见的缺点是并非每个浏览器都会运行您的Javascript扩展,因此您需要在构建过程中添加一个编译步骤,以便将您的代码转换为具有continuation-passing-style回调的常规JS.无论如何,一个有前途的替代方案是Ecmascript 6规范中的生成器 - 虽然目前只有firefox本身支持它们,但有一些项目,如regeneratorTraceur,可以将它们编译回回调.还有其他项目创建自己的异步语法(因为es6生成器当时没有出现).在这个类别中,你会发现诸如tamejsIced Coffeescript之类的东西.最后,如果您使用Node.js,您还可以查看Fibers.


我的推荐:

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

但是,如果您希望编写大量复杂且深度集成的异步代码,我强烈建议您至少查看基于编译器的替代方法.

  • @BrettRyan:实际上,我主要使用Dojo工具包的东西,所以我对他们的promise库有很多经验,对替代品没有多少经验.所有不同的样式应该能够完成你需要的所有非阻塞内容,所以你应该更多地考虑编程风格.如果我现在必须开始做一些事情,我会考虑使用CPS编译器 - 我真的不知道它实际上会如何实现,但现在我已经厌倦了手动编写CPS代码并希望得到某些东西更好. (2认同)