node.js模块:Async vs Fibers.promise vs Q_oper8

只是想知道是否有人可以给我比较这些模块之间的权衡处理asynchronous事件。 具体来说,我有兴趣知道使用Async而不是Fibers.promise的原因,目前我至less在我的testing代码中使用了它。 特别是,我在Fibers.promise中看到的一个主要优势是我可以保持堆栈链前端分叉,使得最终可以使用try { } catch { } finally ,并且还允许我确保在请求已经处理了响应结束。

有人使用Q_oper8吗? 我在另一个网页上发现了这个,只是想知道如果这已经死了,或者我应该检查一下。

我从来没有听说过Q_oper8,所以我不能评论它,但我会从另一个方向来看这个。 我首先听说了asynchronous,其次是Fibre(及其辅助库),实际上我不喜欢后者。

纤维的缺点

对其他Javascript开发人员不熟悉

Fiber通过编译的Fiber本地方法向Javascript介绍了协同例程的概念,该方法接pipe传递给它的Javascript代码的解释,拦截调用以便跳回等待的协同例程。

这对你来说可能并不重要,但是如果你需要在一个团队中工作,那么你就必须把这个概念教给你的成员(或者希望他们对于Go等其他语言的概念有经验)。

没有Windows支持

所以,为了使用Fibre或者写在它上面的任何库,你必须先为你的平台本地编译它。 我不使用Windows,但请注意,光纤在Windows上不受支持,因此限制了您自己的库的实用程序。 这意味着你不会find用Fiber编写的通用Node.js库(反正你也许不会这样做,因为它增加了一个昂贵的编译步骤,否则你会避免使用asynchronous)。

浏览器不兼容

这意味着使用Fiber编写的任何代码都无法在浏览器中运行,因为无法将本机代码与浏览器混合(即使浏览器用户也希望您),即使您编写的所有内容都是“Javascript “(这是合法的Javascript,但语义上不)。

更困难的debugging

虽然“callback地狱”在视觉上可能不那么令人满意,但是持续传递风格对于Co-Routines来说确实有一件非常好的事情 – 您确切地知道调用堆栈发生问题的位置,并且可以向后追踪。 同程序在程序中的多个点input函数,可以退出三种调用returnthrowyield() ,后者也是返回点。

使用协同例程,可以在两个或多个“同时”运行的函数之间交叉执行,并且在事件循环中同时运行多个协同例程。 使用传统的callback函数,可以保证函数的外部范围在执行函数时是静态的,所以如果需要的话只需要检查一次外部variables。 协程需要在每个yield()之后运行这些检查(因为它与原始协程的使用将被翻译成真正的Javascript中的callback链)。

基本上,我认为co-routine的概念比较难处理,因为它必须存在 Javascript事件循环内部 ,而不是一个实现它的方法。

什么使asynchronous“更好”?

更糟糕的是更好

实际上,这是“更好更好”的想法。 Async是一种纯粹的Javascript解决scheme,可以像化妆一样覆盖它们,而不是扩展Javascript语言来尝试去除它的瑕疵(并创build新的瑕疵)。

控制stream程显式

asynchronous函数描述了需要跨越事件循环屏障的不同types的逻辑stream程,库文件覆盖了实现该逻辑所需的callback代码的实现细节,而且您只需提供它应该以大致线性顺序运行的函数他们将在整个事件循环中执行。

如果你愿意放弃asynchronous方法参数的第一个缩进级别,你就没有额外的缩进,而只有less量的额外的function(callback) {声明,像这样:

 var async = require('async'); var someArray = [1, 2, 3, 4, 5, 6, 7, 8, 9]; async.forEach(someArray, function(number, callback) { //Do something with the number callback(); }, function(err) { //Done doing stuff, or one of the calls to the previous function returned an error I need to deal with }); 

在这种情况下,您知道代码所使用的所有variables只能在您的代码运行之前更改(如果代码没有更改),那么您可以更容易地进行debugging,并且只有一个“返回”机制: callback() 。 你要么callback没有任何成功或通过callback错误时出现错误。

代码重用不难

上面的例子使得代码重用变得困难,但不一定是。 您始终可以传入命名函数作为参数:

 var async = require('async'); // Javascript doesn't care about declaration order within a scope, // so order the declarations in a way that's most readable to you async.forEach(someArray, frazzleNumber, doneFrazzling); var someArray = [1, 2, 3, 4, 5, 6, 7, 8, 9]; function frazzleNumber(number, callback) { // Do something to number callback(); } function doneFrazzling(err) { // Do something or handle error } 

function性,而不是必要的

asynchronous模块不鼓励使用命令式stream量控制,并鼓励(要求跨越事件循环的部分)使用stream量控制function。

函数风格的优点是可以轻松地重用循环体或你的条件体,并且你可以创build新的控制stream“动词”,更好地匹配你的代码stream(由非常存在的asynchronous库),就像为函数调用顺序实现依赖图parsing的async.auto控制stream方法一样。 (您可以指定一系列命名的函数,并列出依赖于执行的其他函数(如果有的话),并且首先auto运行“独立”函数,然后运行下一个可以运行的函数。 )

您不必编写代码来适应您的语言规定的命令式风格,而是根据问题的逻辑编写代码,并实施“粘合”控制stream程以实现这一目标。

综上所述

光纤,由于其扩展Javascript语言的本质,不能在Node.js中开发一个大的生态系统,尤其是当Async在外观部门获得80%的方法,并且在Javascript中没有其他协同例程的缺点时。

简短的回答:

  • asynchronous是一个纯粹/经典的JavaScript解决scheme来pipe理单线程asynchronous
  • Fibers是用于创build协同程序的node.js扩展。 它包括一个pipe理单线程asynchronous的期货库。
  • 还有很多其他期货库(下面列出),不需要JavaScript的扩展。
  • Q_oper8是一个用于pipe理多进程并发的node.js模块

请注意,这些都不提供“线程”,所以没有人可以说是做multithreading(尽pipe也有一个node.js扩展名: threads_a_gogo )。

asynchronous与光纤/期货

asynchronous

Async和Fibers / futures是解决相同问题的不同方法:pipe理asynchronousparsing依赖关系。 与其他许多试图解决这个问题的库相比,asynchronous似乎有更多的“花里胡哨”,这在我看来使情况变得更糟(更多的认知开销 – 即更多的学习废话)。

在JavaScript的基本asynchronous看起来像这样:

 asyncCall(someParam, function(result) { useThe(result); }); 

如果你的情况需要的不仅仅是基本的asynchronous性,就像你需要两个asynchronous调用的结果一样,你可能会这样做:

 asyncCall1(someParam, function(result0) { asyncCall2(someParam, function(result1) { use(result0, result1); } }); 

已经开始看起来像callback地狱。 另外它的低效率是因为第二个调用等待第一个调用完成,即使它不依赖于它,更不用说代码甚至不做任何合理的error handling。 asynchronous提供了一个更有效的写一个解决scheme:

 async.parallel([ function(callback) { asyncCall1(someParam, function(result0) { callback(null,result0); }, function(callback) { asyncCall1(someParam, function(result1) { callback(null,result1); }, } ], function(err, results) { use(results[0], results[1]); }); 

所以对我来说,这比回拨地狱更糟糕,但是对于他自己我想。 尽pipe这很丑陋,但它允许两个调用同时发生(只要他们进行非阻塞IO调用或类似的东西)。 asynchronous有更多的选项来pipe理asynchronous代码,所以如果你有兴趣看看文档 。

input纤维/期货

Fibers模块的协同程序包括一个期货库,它使用协同程序将asynchronous事件重新注入当前延续(future.wait())。

Fibers与大多数其他的期货库不同,因为它允许当前的持续等待一个asynchronous事件 – 意味着它不需要使用callback函数,以便从asynchronous请求中获取值 – 允许asynchronous代码变为同步等。 阅读关于协程的更多信息。

Node.js具有像readFileSync这样的io函数,它可以让你在函数内部等待函数。 这不是通常在JavaScript中完成的事情,也不是可以用纯JavaScript编写的东西 – 它需要像Fibers这样的扩展。

回到上面的同一个asynchronous例子,这就是光纤/期货的样子:

 var future0 = asyncCall1(someParam); var future1 = asyncCall2(someParam); use(future0.wait(), future1.wait()); 

这非常简单,就像Async那样高效。 它以一种高效的方式避免了回拨 – 地狱。 虽然有(次要的)缺点。 戴维·埃利斯(David Ellis)夸大了许多缺点,所以我将在这里重复唯一有效的一个:

浏览器不兼容

由于Fibers是一个node.js扩展名,它将不兼容浏览器。 这将使共享使用光纤无法使用node.js服务器和浏览器的代码。 然而,有一个强有力的论点是,你想在服务器上的大多数asynchronous代码(文件系统,数据库,networking调用)是不是你想要在浏览器上的代码(AJAX调用)。 也许超时碰撞,但似乎是这样。

除此之外, streamline.js项目有能力填补这个空白。 似乎它有一个编译过程,可以将使用同步和期货的streamline.js代码转换为使用callback风格的纯JavaScript,类似于现在不支持的Narrative Javascript 。 Streamline.js可以在后台使用两种不同的机制,一个是node.js Fibers,另一个是ECMAScript 6生成器,最后一个是我已经提到的callback式JavaScript。

debugging比较困难

这似乎是一个有效的,如果轻微,抱怨。 即使你只是计划使用光纤/期货,而不是使用协同作为其他任何事情,但由于意外的function退出(和入口)点,可能仍然存在令人困惑的上下文切换。

在JavaScript中引入先发制人

这可能是光纤最主要的问题,因为它有可能(不太可能)引入难以理解的错误。 基本上,由于光纤yield可能导致一组代码临时退出到另一个未确定的function,因此可能会读取或引入一些无效状态。 看到这篇文章的更多信息。 就我个人而言,我认为纤维/期货和类似结构的令人难以置信的清洁是非常值得的罕见阴险的错误。 更多的错误是由可怕的并发代码造成的。

无效的抱怨

  • 不是在窗户上:这是不正确的了
  • 对协程的不熟悉:A.陌生并不是避开某些东西的理由。 如果它的好,不pipe你有多熟悉它。 B.虽然协程和产量可能不熟悉,但期货是一个容易理解的概念。

其他期货图书馆

有许多实施期货的图书馆,这个概念可能被称为“期货”,“延期对象”或“承诺”。 这包括诸如async-future , streamline.js , Q , when.js , 混杂 , jQuery延期 , coolaj86的未来 , kriszyp的承诺以及Narrative Javascript等库 。

其中大多数使用callback来解决期货,这解决了许多Fibers介绍的问题。 但是,它们并不像纤维/期货那么干净,而且比Async更清洁。 下面是使用我自己的asynchronous未来的同一个例子:

 var future0 = asyncCall1(someParam); var future1 = asyncCall2(someParam); Future.all([future0, future1]).then(function(results) { use(results[0], results[1]) }).done() 

Q_oper8

Q_oper8真的是一个不同的野兽。 它使用一系列进程在队列中运行作业。 由于JavaScript是单线程 *,并且JavaScript没有可用的本地线程,所以进程是利用node.js中的多个处理器的常用方式。 Q_oper8旨在作为使用node.js的child_process模块​​pipe理进程的替代scheme。

你也应该检查步骤 。

它只处理asynchronous可以做的一小部分,但我认为代码更容易阅读。 处理一系列事情的正常情况是很好的,其中一些事情是并行发生的。

我倾向于使用Step作为我的逻辑的一部分,然后偶尔使用asynchronous,当我需要在串行或并行执行中重复应用方法(即 – 调用此函数直到或在此数组的每个元素上调用此函数)。

我在客户端上使用jQuery的Deferredfunction,而在服务器上使用jQuery Deferred来代替嵌套的callback。 它极大地减less了代码并使事情变得可读。

http://techishard.wordpress.com/2012/05/23/promises-promises-a-concise-pattern-for-getting-and-showing-my-json-array-with-jquery-and-underscore/

http://techishard.wordpress.com/2012/05/29/making-mongoose-keep-its-promises-on-the-server/