javascript 在javascript中链接异步调用的正确方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9432587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the correct way to chain async calls in javascript?
提问by Brett Ryan
I'm trying to find the best way to create async calls when each call depends on the prior call to have completed. At the moment I'm chaining the methods by recursively calling a defined process function as illustrated below.
当每个调用取决于先前调用是否完成时,我试图找到创建异步调用的最佳方法。目前,我通过递归调用定义的过程函数来链接方法,如下所示。
This is what I'm currently doing.
这就是我目前正在做的事情。
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();
}
}
})();
I would then call this as follows
然后我会这样称呼它
var log = function(message) {
// Impl removed.
}
syncProduct.start(function() {
log("Product Sync Complete!");
}, log);
While this works perfectly fine for me I can't help but think there has to be a better (simpler) way. What happens later when my recursive calls get too deep?
虽然这对我来说非常好,但我不禁认为必须有更好(更简单)的方法。当我的递归调用太深时会发生什么?
NOTE: I am not using javascript in the browser but natively within the Titanium framework, this is akin to Javascript for Node.js.
注意:我没有在浏览器中使用 javascript,而是在 Titanium 框架中使用 javascript,这类似于 Node.js 的 Javascript。
回答by hugomg
There are lots of libraries and tools that do async chaining and control-flow for you and they mostly come in two main flavours:
有很多库和工具可以为您执行异步链接和控制流,它们主要有两种主要风格:
Control-flow libraries
For example, see async, seqand step(callback based) or Qand futures(promise based). The main advantage of these is that they are just plains JS libraries that ease the pain of async programming.
In my personal experience, promise-based libraries tend to lead to code that looks more like usual synchronous code, since you return values using "return" and since promise values can be passed and stored around, similarly to real values.
On the other hand, continuation-based code is more low level since it manipulates code paths explicitely. This can possibly allow for more flexible control flow and better integration with existing libraries, but it might also lead to more boilerplaty and less intuitive code.
Javascript CPS compilers
Extending the language to add native support for coroutines/generators lets you write asynchronous code in a very straightforward manner and plays nice with the rest of the language meaning you can use Javascript if statements, loops etc instead of needing to replicate them with functions. This also means that its very easy to convert previously sync code into an async version. However, there is the obvious disadvantage that not every browser will run your Javascript extension so you will need to add a compilation step in your build proccess to convert your code to regular JS with callbacks in continuation-passing-style. Anyway, one promising alternative is the generators in the Ecmascript 6 spec - while only firefox supports them natively as of now, there are projects such as regeneratorand Traceurto compile them back to callbacks. There are also other projects that create their own async syntax (since es6 generators hadn't come up back then). In this category, you will find things such as tamejsand Iced Coffeescript. Finally, if you use Node.js there you could also take a look at Fibers.
控制流库
例如,请参阅async、seq和step(基于回调)或Q和期货(基于承诺)。这些的主要优点是它们只是简单的 JS 库,可以减轻异步编程的痛苦。
根据我的个人经验,基于 Promise 的库倾向于导致代码看起来更像通常的同步代码,因为您使用“return”返回值,并且因为 Promise 值可以传递和存储,类似于真实值。
另一方面,基于延续的代码更底层,因为它显式地操作代码路径。这可能允许更灵活的控制流和与现有库的更好集成,但它也可能导致更多样板和不那么直观的代码。
Javascript CPS 编译器
扩展语言以添加对协程/生成器的本机支持,让您可以以非常简单的方式编写异步代码,并与语言的其余部分很好地配合,这意味着您可以使用 Javascript if 语句、循环等,而无需使用函数复制它们。这也意味着很容易将以前的同步代码转换为异步版本。但是,有一个明显的缺点,即并非每个浏览器都会运行您的 Javascript 扩展,因此您需要在构建过程中添加一个编译步骤,以将代码转换为具有 continuation-passing-style 回调的常规 JS。无论如何,一种有前途的替代方案是 Ecmascript 6 规范中的生成器——虽然目前只有 Firefox 原生支持它们,但有诸如regenerator和Traceur将它们编译回回调。还有其他项目创建了自己的异步语法(因为那时 es6 生成器还没有出现)。在此类别中,您会找到诸如tamejs和Iced Coffeescript 之类的东西。最后,如果你在那里使用 Node.js,你也可以看看Fibers。
My recomendation:
我的建议:
If you just want something simple that won't complicate your build proccess, I would recomend going with whatever control-flow library best fits your personal style and the libraries you already use.
如果您只是想要一些不会使您的构建过程复杂化的简单东西,我建议您使用最适合您个人风格和您已经使用的库的任何控制流库。
However, if you expect to write lots of complicated and deeply-integrated asynchronous code, I would strongly recommend at least looking into a compiler-based alternative.
但是,如果您希望编写大量复杂且深度集成的异步代码,我强烈建议您至少查看基于编译器的替代方案。