node.js modules: Async vs Fibers.promise vs Q_oper8 - multithreading

Just wondering if anyone could give me a comparison of trade-offs between these modules for handling async events. Specifically, I'm interested in knowing about reasons to use Async instead of Fibers.promise, which I am using quite extensively at least in my test code right now. In particular, one of the major pluses I see in Fibers.promise is that I can keep the stack chain front bifurcating, making it possible to use try { } catch { } finally, and also allowing me to ensure that after a request has been handled that the response is ended.
Is anyone using Q_oper8? I found this on another page and was just wondering if that's already dead or if its something I should check out.

I've never heard of Q_oper8, so I can't comment on it, but I'll come at this from the other direction. I heard about async first and Fiber (and its helper libraries) second, and I don't like the latter, actually.
The Downsides of Fiber
Unfamiliarity for other Javascript developers
Fiber introduces the concept of co-routines to Javascript via a compiled Fiber native method that takes over the interpretation of the Javascript code passed to it, intercepting calls to yield to jump back to the waiting co-routine.
This may not matter to you, but if you need to work on a team, you'll have to teach the concept to your members (or hope they have experience with the concept from other languages, like Go).
No Windows Support
So, in order to use Fiber or any of the libraries written on top of it, you'll have to natively compile it for your platform first. I don't use Windows, but note that Fiber is not supported on Windows, so that restricts the utility of your own library off-the-bat. Which means you won't be finding general-purpose Node.js libraries written in Fiber at all (and you probably wouldn't have, anyways, since it adds a costly compilation step that you'd otherwise avoid with async).
Browser Incompatible
This means any code you write using Fiber will not be able to run in the browser, because you can't mix native code with the browser (nor would I as a browser user want you to), even if everything you write is "Javascript" (it's syntatically Javascript, but semantically not).
More Difficult Debugging
While the "callback hell" may be less visually pleasing, Continuation-Passing Style does have one very good thing going for it over Co-Routines -- you know exactly where a problem has occurred from the call stack and can trace backwards. Co-Routines enter the function at more than one point in the program, and can exit from three kinds of calls: return, throw and yield(), where the latter is also a return point.
With co-routines, you have cross-execution between two or more functions running "simultaneously", and you may have more than one set of co-routines running at the same time on the event loop. With traditional callbacks, you're guaranteed that the outer scope of the function is static during the execution of said function, so you only need to check those outer variables once if they're needed. Co-routines need these checks to be run after every yield() (since it's usage with the originating co-routine would be translated into a callback chain in real Javascript).
Basically, I think the co-routine concept is made more difficult to work with because it has to exist inside of the Javascript event loop, rather than being a method to implement one.
What makes Async "better"?
Worse is Better
It's sort of the "worse-is-better" idea, actually. Rather than extend the Javascript language to try and get rid of its warts (and create new ones, in my opinion), Async is a pure-Javascript solution to cover them up, like makeup.
Control flow explicit
The Async functions describe different types of logic flow that needs to cross the event loop barrier, and the library covers up the implementation details of the callback code needed to implement that logic, and you just provide it functions it should run in roughly the linear order they will execute across the event loop.
If you're willing to drop the first indentation level around the async methods' arguments, you have no extra indentation versus Co-Routines and only a minor number of extra lines of function(callback) { declarations, like this:
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
});
In this case, you know that all of the variables your code is using could only have been changed before your code is run if they weren't changed by your code, so you can debug easier, and there is only one "return" mechanism: callback(). You either callback with nothing on success or pass the callback an error when something's gone wrong.
Code reuse not difficult
The above example makes code reuse difficult but it doesn't have to be. You can always pass in named functions as the parameters:
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
}
Functional, not imperative
The async module discourages the use of imperative-style flow control and encourages (requires, for the parts that cross the event loop) the use of functions for flow control.
The advantage of the functional style is that you can easily re-use the body of your loop or your conditional, and that you can create new control flow "verbs" that better match the flow of your code (demonstrated by the very existence of the async library), like the async.auto control flow method that implements dependency graph resolution for function call order. (You specify a series of named functions and list the other functions, if any, that it depends on to execute, and auto runs first the "independent" functions then the next function that can run based on when its dependent functions have finished running.)
Rather than writing your code to fit the imperative style dictated by your language, you write your code as the logic of the problem dictates, and implement the "glue" control flow to get it to happen.
In Summary
Fiber, by its very nature of extending the Javascript language, cannot develop a large ecosystem within Node.js, especially when Async gets 80% of the way on the looks department, and has none of the other downsides of co-routines in Javascript.

The short answer:
Async is a pure/classic javascript solution to managing single-thread asynchronousity
Fibers is a node.js extension for creating coroutines. It includes a futures library for managing single-thread asynchronousity.
There are many other futures libraries (listed below) that don't require an extension of javascript.
Q_oper8 is a node.js module for managing multi-process concurrency
Note that none of these offer "threads" and so none can be said to do multithreading (though there is a node.js extension for that too: threads_a_gogo).
Async vs Fiber/futures
Async
Async and Fibers/futures are different ways to solve the same problem: managing asynchronously resolving dependencies. Async seems to have many more "bells and whistles" than many other libraries that try to solve this problem, which in my opinion makes it worse (much more cognitive overhead - ie more crap to learn).
In javascript basic asynchronisity looks like this:
asyncCall(someParam, function(result) {
useThe(result);
});
If you have a situation that requires more than just basic asynchronisity, like where you need the results of two asyncronous calls, you might do something like this:
asyncCall1(someParam, function(result0) {
asyncCall2(someParam, function(result1) {
use(result0, result1);
}
});
Already starts to look like callback hell. Also its inefficient because the second call is waiting for the first call to complete even though it isn't dependent on it, not to mention the code doesn't even do any sort of reasonable error handling. Async provides one solution to writing it a little more efficiently:
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]);
});
So to me, thats rather worse than callback hell, but to each his own I suppose. Despite it being ugly, it allows both calls to happen simultaneously (as long as they make non-blocking IO calls or something like that). Async has many more options for managing asynchronous code, so if you're interested take a look at the documentation.
Enter fiber/futures
The coroutines the Fibers module includes a futures library that uses coroutines to re-inject asynchronous events back into the current continuation (future.wait()).
Fibers is different from most other futures libraries because it allows the current continuation to wait on an asynchronous event - meaning it doesn't require the use of callbacks in order for you to get a value back from an async request - allowing asynchronous code to become synchronous-like. Read about coroutines for more about that.
Node.js has io functions like readFileSync, which lets you wait on the function in-line while it gets the file for you. This is not something that is normally done in javascript, and isn't something that can be written in pure javascript - it requires an extension like Fibers.
Going back to the same asynchronous example above, this is what it would look like with fibers/futures:
var future0 = asyncCall1(someParam);
var future1 = asyncCall2(someParam);
use(future0.wait(), future1.wait());
This is drastically simpler and just as efficient as the Async mess up there. It avoids callback-hell in an elegant efficient way. There are (minor) downsides though. David Ellis overstated many of the downsides, so I'll repeat the only valid one here:
Browser Incompatibility
By virtue of Fibers being a node.js extension, it will not be compatible with browsers. This will make sharing code that uses fibers impossible with both a node.js server and the browser. However, there is a strong argument that most asynchronous code you want on the server (filesystem, database, network calls) is not the same code you want on a browser (ajax calls). Maybe timeouts collide, but that seems like it.
Beyond that, the streamline.js project has the ability to bridge this gap. Seems like it has a compilation process that can transform streamline.js code using synchronization and futures into pure javascript using the callback style, similar to the now unsupported Narrative Javascript. Streamline.js can use a couple different mechanisms behind the scenes, one being node.js Fibers, another being ECMAScript 6 generators, and the last being translation into callback-style javascript which I already mentioned.
More difficult debugging
This one seems like a valid, if minor, gripe. Even if you're just planning on using fibers/futures, and not using coroutines for anything else, there might still be confusing context switches because of unexpected function exit (and entrance) points.
Introduces pre-emptiveness into javascript
This is probably the most major problem with fibers, since it has the possibility (however unlikely) of introducing hard-to-understand bugs. Basically, because a Fiber yield can cause a temporary exit of a set of code to another undetermined function, its possible that some invalid state can be read or introduced. See this article for more info. Personally, I think the incredible cleanness of fibers/futures and similar structures is well worth the rare insidious bugs. Many more bugs are caused by awful concurrency code.
Invalid gripes
Not on windows: this just isn't true anymore
Unfamiliarity with coroutines: A. Unfamiliarity is never a reason to shun something. If its good its good, regardless of how familiar you are with it. B. While coroutines and yields may be unfamiliar, futures are an easy concept to understand.
Other futures libraries
There are many libraries that implement futures, where the concept may be called "futures", "deferred objects", or "promises". This includes libraries like async-future, streamline.js, Q, when.js, promiscuous, jQuery's deferred, coolaj86's futures, kriszyp's promises, and Narrative Javascript.
Most of these use callbacks to resolve the futures, which get around many of the problems Fibers introduces. However, they aren't quite as clean as fibers/futures, tho they are far cleaner than Async. Here's the same example again using my own async-future:
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 is really a different beast. It runs jobs in a queue using a pool of processes. Since javascript is single-threaded*, and javascript doesn't have native threading available, processes are the usual way to take advantage of more than one processor in node.js. Q_oper8 is intended as an alternative to managing processes using node.js's child_process module.

You should also check out Step.
It handles only a small subset of what async can do, but I think the code is much easier to read. It's great for just handling the normal case of doing a sequence of things, with some of those things happening in parallel.
I tend to use Step for the bulk of my logic, and then use async occasionally when I need to apply methods repeatedly in serial or parallel execution (ie - call this function until, or call this function on each element of this array).

I'm using jQuery's Deferred functionality on the client and jQuery Deferred for nodejs on the server in place of nested callbacks. It has greatly reduced the code and made things so readable.
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/

Related

Why do coroutines have futures?

Once you have coroutines you can create pipelines (haskell: pipes, conduits; python: generators) or cooperative event loops (python: curio). Once you have futures, it appears you can do the same; pipelines (rust: futures-rs) and event loops (rust: tokio). Since futures aren't cooperative they require a callback-based (even poll-based futures require callbacks) scheduler to execute blocking tasks within a thread or process pool. What benefits are there to combining futures (library-level) with coroutines (language-level) as these languages do: (python: asyncio), (rust: rfc), (ecmascript 6+). Fundamentally they seem to be conflicting solutions to the same problem.
I'm not looking for a pro/con comparison, and I don't buy the argument that futures are "one-shot" coroutines. Just look at rust, which built an entire state-machine-based event framework using just futures. I want to know why python/asyncio and javascript both require coroutines together with futures. Why rust is planning on adding coroutines to its futures? Does it have to do with composability of events? Or the implicit stack of coroutines versus the explicit stack of continuation-passing futures? Not that I completely understand this argument, as both futures and coroutines are implemented using continuations... Or does it have something to do with direct vs indirect style?
These are all different (though related) ideas with different amounts of power.
A future is an abstraction that lets you begin a process and then yield back to a handler, that is chosen by the original caller, when the process is done.
A generator is more powerful than a future because it can yield multiple times. You can implement futures on top of generators.
A coroutine is more powerful than a generator because it can choose who to yield to, instead of only to the caller. For example it can yield to another coroutine. You can implement generators on top of coroutines.
Why would you use the less powerful tool, when more powerful ones are available? Sometimes the less powerful tool is the right tool for the job. It's useful to statically encode your program's invariants using types, because it can give you certainty about what something can't do.
For example, when making a REST call to a remote server, a future is probably sufficient. If the REST client exposed a generator, you'd have to deal with the possibility that it could yield multiple times, even though you know there is only going to be one result. If it exposed a coroutine, you'd have to consult the documentation to work out exactly how you're supposed to interact with it - even though you actually only need to do one thing, which is obvious when you're dealing with a future.

How can I use multi threading in node js?

I have a program and I want that program to work for several users, with different passwords. How can I solve this problem with using node js?
I use instagram-private-api and want to login multiple accounts.
I think you are missing the point of node js. The reason why many other languages use threading (C#, java, c++, etc) is because all the code written is synchronous. Rather, it executes line by line. Line 10 doesn't execute until line 9 finishes. However, this is not to say they don't have asynchronous implementations. These days there are ways to write asynchronous syntax in those languages, but generally speaking, they're mostly all synchronous.
Enter javascript and the nodejs platform. 95% of it is asynchronous (95% is a total guess and more of a figure of speech, but there are "synchronous" functions... which should be used very rarely and, generally just avoided). So node uses a "single thread", but operates around something called an event loop. Not going to go into details about that here, but you can google on what the event loop is and how it works... other folks will explain it better than I can. Thus, because of that design, and because of the asynchronous nature, you really don't need threading in your nodejs application.
Sounds like you need to just go get your feet wet with node. Take some tutorials, etc. It's quite trivial to handle multiple users at once, and no threading is necessary.
Also, if none of that makes sense, then also go read up on "synchronous vs asynchronous".
Node js is a single threaded language but has asynchronous functions. For example if we use a loop in node js then as node js is single threaded then nothing can be executed until that loop finishes but this is not the case. We can use async functions which will run in event loop side by side with the main thread.

Async vs Deasync in reality

The background
I'm writing my next server project in node. The previous version was written in language D, which is majorly an synchronized implementation. We all know, that JS uses a lot of async This is good for performance, but hard to maintain (at least for me). Because node and its node modules might use different async approach (callback, promise and await/async), which makes the code looks not in a consistent style. I'm looking for a balanced approach, that not only can create a high quality and performance node application, but fit the common programming style.
The problem
After first round prototyping, I have my first server. When I start the server, it will first read configuration and then load a set of modules. I expect them to be loaded sequentially. But as I mentioned above, node modules might work in async way. I expect module b to be loaded exactly when module a is loaded, I must use Promise pattern. I have to write code in crazy way, although Promise is already a very programmer friendly approach.
No, I go to the other direction. Currently I choose deasync, which is a gyp module for node. It can really blocks the code execution like this.
const deasync = require('deasync');
let done = false;
loadModule1Async((err, result) => {
done = true;
});
deasync.loopWhile(() => !done);
done = false;
loadModule2Async((err, result) => {
done = true;
});
deasync.loopWhile(() => !done);
OR even more magical like this
const deasync = require('deasync');
const loadModule1Sync = deasync(loadModule1Async);
const loadModule2Sync = deasync(loadModule2Async);
try {
loadModule1Sync();
loadModule2Sync();
} catch(ex) {
console.error(ex);
}
IMO, the deasync way is more straightforward to me, but I have two concerns:
It need to be compiled against the target platform, so that the deployment process will be complicated for production.
I checked its issue list. There are some known serious issue, e.g. hanging in some extream cases.
The question
Can the coming new feature async/await really do the same thing as deasync does? If it is never gonna happen due to the JS nature. I might stop thinking about this.
Please share me some lights on the way to node.
I don't know too much about how deasync works, I took a look at it and looks very convenient, but I don't think it's thought to be used through all your code in a server.
little bit performance downgrade
It depends on your case, but it could be more than a little downgrade. You are wrapping all your asynchronous methods in your code, that does not sound good in general. Doing a benchmark could be a good idea.
Other thing:
Because node and its node modules might use different async approach (callback, promise and await/async)
In general modules follow callback style, Promise style, or both of them. Most of the big ones are compatibles with both of them (in general if you don't pass a callback a Promise is returned).
async/await is different, this works on top of Promises, so a module method that returns a Promise can be used with async/await in your code.
So answering your question, I would stick with Promises in the whole code, it's the tendency now, and in general they are easier to deal with, compared to callbacks.
To me async/await is the easiest way, since it keeps calls asynchronous, but the code is written in a synchronous way. Sadly at the moment async/await is only usable in Node.js through a flag, so it's not recommended to be used in production.

Koa / Co / Bluebird or Q / Generators / Promises / Thunks interplay? (Node.js) [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I'm investigating building a web app in part with Koa, but I don't quite have a handle on the hows, whens, and whys of choosing between - and applying - the range of supportive "making async easier" technologies/approaches (listed below).
Overall the disparate guidance on the web about this subject still leaves things blurry, especially in respect to evolving best practices, or at least better ones, and under what scenarios. There seems to be little or nothing on the web that puts it all in context.
I'm hoping the responses to this big arse sprawling post can correct that. Also maybe the questions below can inspire someone to write a thorough blog post or the like to address this matter. My sense is I'm not even close to the only one who would benefit from that.
So I'd be pleased if the bright community could help answer and provide clarity to the following questions in respect to the technologies listed below (in bold type):
-- a) How, and under what circumstance (as applicable) are they complements, supplements, substitutes, and/or overlapping solutions to one another?
-- b) What are their trade-offs in respect to speed-performance, error handling ease, and debugging ease?
-- c) When, where, and why may it be better to use "this" versus "that" technology, technologies-combo, and/or approach?
-- d) Which technologies or approaches, if any, may be "dimming stars".
(Hoping that the opinions that are part of answers can be well explained.)
==============================
Technologies:
* Koa *
My understanding:
Koa is a minimal foundation for build Node apps geared for taking advantage of ECMAScript-6 features, one feature in particular being generators.
* Co *
My understanding:
-- Co is a library of utilites for running ECMAScript-6 generators (which are native to Node .011 harmony), with the goal to allieve some/much(?) of the need to write boilerplate code for running and managing generators.
-- Co is intrinsically part of Koa(?).
Specific questions:
-- If and how does one use Co differently in Koa than in a non-Koa context. In other words, does Koa wholly facade Co?
-- Could Co be replaced in Koa with some other like generator library if there is/was a better one? Are there any?
* Promise Libraries such as "Q" and Bluebird *
My understanding:
-- They are in a sense "polyfills" for implmententing the Promises/A+ spec, if and until Node natively runs that spec.
-- They have some further non-spec convenience utilities for facilitating the use promises, such as Bluebird's promisfyAll utility.
Specific questions:
-- My understanding is the ECMAScript-6 spec does/will largely reflect the Promises/A+ spec, but even so, Node 0.11v harmony does not natively implement Promises. (Is this correct?) However when it does, will technologies such as Q and Bluebird be on their way out?
-- I've read something to the effect that "Q" and Bluebird support generators. What does this mean? Does it mean in part that, for example, they to some degree provided the same utility as Co, and if so to what degree?
* Thunks and Promises *
I think I have an fair handle on what they are, but hoping someone can provide a succinct and clear "elevator pitch" definition on what each is, and of course, as asked above, to explain when to use one versus the other -- in a Koa context and not in it.
Specific questions:
-- Pro and cons to using something like Bluebird's promisfy, versus say using Thunkify (github com/visionmedia/node-thunkify)?
==============================
To give some further context to this post and its questions, it might be interesting if Koa techniques presented in the following webpages could be discussed and contrasted (especiallly on a pros vs cons basis):
-- a) www.marcusoft . net/2014/03/koaintro.html (Where's the thunks or promises, or am I not seeing something?)
-- b) strongloop . com/strongblog/node-js-express-introduction-koa-js-zone (Again, where's the thunks or promises?)
-- c) github . com/koajs/koa/blob/master/docs/guide.md (What does the "next" argument equate to, and what set it and where?)
-- d) blog.peterdecroos . com/blog/2014/01/22/javascript-generators-first-impressions (Not in a Koa context, but presents the use of Co with a promise library (Bluebird), so I'm assuming the technique/pattern presented here lends itself to usage in Koa(?). If so, then how well?
Thanks all!
I've been working almost extensively with generators for a month now so maybe I can take a stab at this. I'll try to keep the opinions to a minimum. Hopefully it helps clarify some of the confusion.
Part of the reason for the lack of best practices and better explanations is that the feature is still so new in javascript. There are still very few places that you can use generators node.js and firefox being the most prominent, though firefox deviates from the standard a bit.
I would like to note that there are tools like traceur and regenerator that will let you use them for development and allow you to turn them into semi-equivalent ES5 so if you find working with them enjoyable then there's no reason not to start using them unless you're targeting archaic browsers.
Generators
Generators weren't originally thought of as a way to handle asynchronous control flows but they work wonderfully at it. Generators are essentially iterator functions that allow their execution to be paused and resumed through the use of yield.
The yield keyword essentially says return this value for this iteration and I'll pick up where I left off when you call next() on me again.
Generator functions are special functions in that they don't execute the first time they're call but instead return an iterator object with a few methods on it and the ability to be used in for-of loops and array comprehensions.
send(),: This sends a value into the generator treating it as the last value of yield and continues the next iteration
next(),: This continues the next iteration of the generator
throw(): This throws an exception INTO the generator causing the generator to throw the exception as though it came from the last yield statement.
close(): This forces the generator to return execution and calls any finally code of the generator which allows final error handling to be triggered if needed.
Their ability to be paused and resumed is what makes them so powerful at managing flow control.
Co
Co was built around the ability of generators to make handling flow control easier. It doesn't support all of the things that you can do with generators but you can use most of them through it's usage with less boilerplate and headache. And for flow control purposes I haven't found that I needed anything outside of what co provides already. Although to be fair I haven't tried sending a value into a generator during flow control but that does bring up some interesting possibilities....
There are other generator libraries out there some of them that I can think of off the top of my head are suspend, and gen-run. I've tried them all and co offers the most flexibility. Suspend may be a little easier to follow if you're not accustomed to generators yet but I can't say that with authority.
As far as node and best practices go I'd say co is currently winning hands down with the amount of support tools that have been created to go with it. With suspend the most likely runner up.
Co works with both promises and thunks and they are used for yield statement so that co knows when to continue execution of the generator instead of you manually having to call next(). Co also supports the use of generators, generator functions, objects and arrays for further flow control support.
By yielding an array or an object you can have co perform parallel operations on all of the yielded items. By yielding to a generator or generator function co will delegate further calls to the new generator until it is completed and then resume calling next on the current generator, allowing you to effectively create very interesting flow control mechanisms with minimal boilerplate code.
Promises
While I said I'd keep opinions to a minimum I would like to state that to me promises are probably the hardest concept to grasp. They are a powerful tool for maintaining code but they are hard to grasp the inner workings of and can come with quite a few gotchas if used for advanced flow control.
The easiest way that I can think of to explain promises is that they are an object returned by a function that maintains the state of the function and a list of callbacks to call when the a specific state of the object is or has been entered into.
The promise libraries themselves won't be going anywhere anytime soon. They add a great deal of nice to haves for promises included done() which didn't make it into the ES6 spec. Not to mention the fact that the same libraries can be used on the browser and in node we'll have them for a good long while.
Thunks
Thunks are just functions that take a single parameter callback and return another function that they are wrapping.
This creates a closure that allows the calling code to instantiate the function passing in its callback so that it can be told when the method is complete.
Thunks are fairly straight forward to understand and use in my opinion but they aren't the right tool for everything. For example spawn is a major pain to create a thunk for, you can do it but it's not easy.
Thunks vs. Promises
These aren't mutually exclusive and can easily be used together, but it's usually better for your sanity to pick one and stick with it. Or at the very least pick a convention so you can easily tell which is which. Thunks run faster from my experience but I haven't benchmarked it. Most of this is probably because it's a smaller abstraction and doesn't have error handling mechanisms built in.
You'll usually be building something that requires error handling though so the overall performance gains of thunks could easily even out or side in the favor of promises depending on your code.
When to Use
Generators - When you can safely say that your application will be able to run on the bleeding edge, whether it's firefox only for the browser or node > 0.11.3
I've been using them extensively at the company I'm out now and couldn't be happier with the control flow mechanisms and lazy evaluation that they allow.
Promises vs. Thunks - This is really up to you and how comfortable you are working with each. They don't provide the same benefits nor do they solve the same problem. Promises help deal with the async problem directly, thunks just ensure a function takes the needed callback parameter for other code to pass in.
You can use them both together and as long as you can keep it so that it's obvious which is which you won't have a problem.
Promises/Thunks with Generators - I suggest doing this anytime you are using generators for control flow. It's not necessary but it's easier just like using co as an abstraction for control flow with generators is easier. Less code to type, easier maintenance, and less possibilities that you'll hit an edge case that somebody else hasn't run into yet.
Koa
I'm not going to go into a lot of detail on koa. Suffice it to say that is similar to express but written to take advantage of generators. This does give it some unique advantages such as easier error handling and cascading middleware. There were ways to accomplish all of these tasks before but they weren't elegant and sometimes not the most performant.
Special Note:
Generators open up a door of possibilities that we really haven't explored yet. Just like they can be used for control flow when that wasn't their initial design I'm positive they can be used to solve a lot of other problems that we normally have problems with in javascript. It will probably be brighter minds than me that find out how else we can use them but I'd at least start playing around with them and getting a better understanding of what they're capable of. There's still more goodies for generators coming in ES.next.

Node.js control flow: callbacks or promises? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I know there are many control flow libraries for node.js. Some of them let one chain async functions with callbacks (like async, asyncblock, etc), the others use promise concept (Q, deferred, futures, etc). Given a long running script making a series of actions one after another that may fail at any time, which control flow would you prefer and why? What are the pros and cons?
Pros for callbacks:
Simple to understand and create.
Somewhat more efficient, because fewer objects are created and garbage collected.
Node opted for (error,result) callbacks throughout. I recommend following their argument order for consistency. (As opposed to say (result1, result2, result3, error).)
Pros for promises:
Provides a fluent interface, which can sometimes help to mitigate nested callback hell, as shown here. Code appears to flow linearly by chaining .then(foo).then(bar) calls.
A good promises library will let you run many asynchronous operations in parallel, and continue only when they are all completed. The Deferred library does this seamlessly through map, Q has allResolved, and ES6 Promises offer Promise.all(). (This is also possible with callbacks, e.g. using async.parallel(), but not built in.)
A good promises library will let you specify one error handling function which will be called if any of the queued functions fail. To do this with callbacks requires a little boilerplate: if (err) return callback(err); at the start of every callback.
It would make sense to use callbacks near the bottom of the stack, for code which will be run many times per second. Higher up the stack, promises may be preferable as they are easier to read and understand, and can handle errors more elegantly.
It is worth noting that promises can be built from callbacks at runtime. So you can implement your core code in the minimalist callback form, and still expose a promises version of the library if you want to. (As in Q.nfbind().)
I would be interested to hear other pros/cons.
Bonus tip: Always handle errors! With both methods, if you do not handle the error then it will simply disappear, leaving you in the dark about why your code did not work as expected.
Callbacks should always handle if (err) ... and Promises should always have a .catch() if they do not return.
Even if you expect errors sometimes, and don't need to handle those, not handling unexpected errors means you won't hear about errors from developer mistakes such as typos, if the code is changed in future.
An alternative to .catch() for Promises is to listen for unhandled rejections. Personally I use this to issue a warning that .catch() was missing!
I don't think there are many objective pros and cons. Async is very popular (based on npm packages that depend on it).
I like the control flow libraries (specifically async), because it is easier for me to understand. Promises confuse me, while async is easily understandable. I suspect its just a learning curve thing though, and promises would be more readable if I spent the effort in learning them. But should I expect that of people trying to read my code too?
There is a 3rd type too - Fibers. Fibers does not work on Windows yet, but (IMO) offers the clearest syntax for things that should execute in series.
I've been experimenting with a declarative approach with this library: http://chainsjs.org still more work to do on it, but it gives you the ability to define an "execution map" where you can pretty much completely control the flow of execution from a simple mapping.

Resources