--
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
---
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Andrew,For the love of all that is dear to us, Use promises, do not support callbacks, don't even think about supporting both.There is a reason why promises are becoming part of the standard in ECMA 6.
Here are a few of many reasons why to choose promises:- It prevent deep indentation
- It always you to pass on asynchronous operations
- Asyncronous callstacks and consistent error handling ( you want this )- How many types have you typed if (err) throw err or if (err) console.warn(err) ?
- Refactoring in callback styled code is extremely tedious to the point where it would be almost reasonable to say it's impossible
- Improved readability trough more logical control flow
- Integration with coroutines ( you want this )
- It always you to pass on asynchronous operations
- How many types have you typed if (err) throw err or if (err) console.warn(err) ?
- Improved readability trough more logical control flow
- Integration with coroutines ( you want this )
var getTotalFriendBalance = Promise.coroutine(function* (name) {var user, userFriends, x, totalBalance;user = yield db.getUserByName(name);userFriends = yield db.getFriends(user.id);for (x = 0; x < userFriends.length; x++) {totalBalance += (yield db.getAccountInfo(userFriends[x].id)).balance;}return totalBalance;});
--
--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "nodejs" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/nodejs/NpZ4WT1eOnw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to nodejs+un...@googlegroups.com.
You received this message because you are subscribed to the Google Groups "nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
As is well known at this point, I created JavaScript in ten days in May 1995, under duress and conflicting management imperatives--"make it look like Java,"make it easy for beginners," "make it control almost everything in the Netscape browser".
Apart from getting two big things right (first-class functions, object prototypes), my solution to the challenging requirements and crazy-short schedule was to make JavaScript extremely malleable from the start.
Hey greelgorke,Great to get some feedback on my answer, I'll try to clarify my arguments some more here:- It always you to pass on asynchronous operationshuh?// foo returns promisevar futureBar = foo();// you can know pass around futureBar to some other api or use it for later reference// with callbacks you will have to write your own wrapper code to get this type of "asynchronous encapsulation"
- How many types have you typed if (err) throw err or if (err) console.warn(err) ?you actually type this yourself?Off course not, but i have seen it in to much code already.Obviously i forgot if (err) return callback(err);If haven't written in this style anymore for a long time.- Improved readability trough more logical control flowduh. readability is subjective.Off course it's subjective, but chronological reading order is something I tend to value in most code.Just my opinion.- Integration with coroutines ( you want this )huh? how is that connected?An example should clarify this, this uses bluebird:This is obviously a bad use of a database, but the idea is to demonstrate how promises integrate with coroutines.var getTotalFriendBalance = Promise.coroutine(function* (name) {var user, userFriends, x, totalBalance;user = yield db.getUserByName(name);userFriends = yield db.getFriends(user.id);for (x = 0; x < userFriends.length; x++) {totalBalance += (yield db.getAccountInfo(userFriends[x].id)).balance;}return totalBalance;});I challenge you to write this peace of code with only callbacks, I think you will find this syntax is much more intuitive and more pleasant to write.
var getTotalFriendBalance = require('co')(function* (name) {
var user, userFriends, x, totalBalance;
user = yield db.getUserByName.bind(db, name);userFriends = yield db.getFriends.bind(db, user.id);
for (x = 0; x < userFriends.length; x++) {
totalBalance += (yield db.getAccountInfo.bind(db, userFriends[x].id)).balance;}return totalBalance;
})();
--
Alex,Do you have an example of any coroutine / promise library that supports passing in an callback styled function without wrapping / binding ?
You would have to pass in the context and arguments separately for every every call, that seems very cumbersome to me.You could yield a binded function to improve it somehow, but binding on every call sounds like a bad idea as well.
See my counter arguments for bind in the previous post. Wrapping will always be necessary when dealing with callback styled functions and coroutines. That in it self should be an argument against using callback style, imho.
function* getTotalFriendBalance(name) {var user = yield db.getUserByName( name);var userFriends = yield db.getFriends(user.id);for (var x = 0; x < userFriends.length; x++) {var totalBalance = 0;
totalBalance += (yield db.getAccountInfo(userFriends[x].id)).balance;return totalBalance;
}
// And you can call it as:
function* compareBalances(name1, name2) {
return (yield getTotalFriendBalance(name1)) - (yield getTotalFriendBalance(name2));
}
If most of your code is made of galaxy functions calling other galaxy functions (which is the case when you write complex modules) you get very lean code. I'm ready to bet that this code will be faster than code written with promise/coroutine combination because 1) you save the allocation of a wrapper around every function being defined (important if you pass or return async functions in your APIs) and 2) you save the allocation of a promise object in every call. The heart of the galaxy library is a tight loop that deals directly with generator objects.
And BTW, I don't use galaxy directly, I use it indirectly through streamline because 1) streamline gives me a friendlier syntax (yield does not play well in expressions because it is prefix with low precedence) and 2) it is directly compatible with node's callback APIs (no wrappers at all as long as callbacks have the standard node signature).
As Alex (and others) mentioned a few posts above, the callback API is a key convention in the node ecosystem. It is awfully simple and it allows modules to interoperate with each other without any extra wrappers. Promises may be interesting conceptually but they introduce complexity (the post that started this thread). Most of the time you don't need the full power of the promise API. Instead of having your APIs return a full-fledged promise object, you could have it return a simple "function(cb)" that you can call later with a callback to get a result. This is lighter and fully aligned with node's conventions (this is what I call a "future" in streamline).
Also, promises allow for consistent asynchronous error handling at the language level, I like that.
It seems to me that galaxy just tries to be an extremely lightweight promise library pretty much by ignoring the promise standard.
If you just define your asynchronous functions as generators you expect the consumer to know its an async function and not a normal generator. Coroutine's should by opaque promises just like any other async function for consistency.
I actually like the coroutine wrapper from blue bird because its a very clear annotation.
I'm also not convinced by your performance remark, the coroutine function is only called once so doesn't add any complexity, and promises are native language constructs. We need benchmarks.
Also generators by them self have nothing to do with async stacks, you need some sort tracking in the promises or the coroutine runner.
The callback "convention" has absolutely zero standardisation and even tough it is simple its very error prone. It requires you to mix language constructs inside your function interface's, I don't get why anyone would want to adhere to that.
It seems to me that galaxy just tries to be an extremely lightweight promise library pretty much by ignoring the promise standard.
If you just define your asynchronous functions as generators you expect the consumer to know its an async function and not a normal generator. Coroutine's should by opaque promises just like any other async function for consistency.
I actually like the coroutine wrapper from blue bird because its a very clear annotation.
I'm also not convinced by your performance remark, the coroutine function is only called once so doesn't add any complexity, and promises are native language constructs. We need benchmarks.
Also generators by them self have nothing to do with async stacks, you need some sort tracking in the promises or the coroutine runner.
The callback "convention" has absolutely zero standardisation and even tough it is simple its very error prone. It requires you to mix language constructs inside your function interface's, I don't get why anyone would want to adhere to that.
What galaxy demonstrates is that generators are sufficient. You can do all you want with generators, you don't need promises (or any other abstraction) around them.
In the node.js ecosystem "any other async function" is a function with a callback, not a function that returns a promise.
function* projectLineCountsParallel() { var future1 = galaxy.spin(countLines(__dirname + '/../examples')); var future2 = galaxy.spin(countLines(__dirname + '/../lib')); var future3 = galaxy.spin(countLines(__dirname + '/../test')); var total = (yield future1()) + (yield future2()) + (yield future3()); console.log('TOTAL: ' + total); return total; }
If you want an annotation, just add a comment.
Regarding performance, function wrappers are not always static...
It is the de facto standard in the node.js ecosystem. And it is more efficient!
On Friday, April 18, 2014 12:59:16 AM UTC+2, willem dhaeseleer wrote:
It seems to me that galaxy just tries to be an extremely lightweight promise library pretty much by ignoring the promise standard.
I actually like the coroutine wrapper from blue bird because its a very clear annotation.
What galaxy demonstrates is that generators are sufficient. You can do all you want with generators, you don't need promises (or any other abstraction) around them.
In the node.js ecosystem "any other async function" is a function with a callback, not a function that returns a promise.Claiming that promises ( or any other abstraction ) or not required seems false to me. Here is an example from galaxy's readme:function* projectLineCountsParallel() { var future1 = galaxy.spin(countLines(__dirname + '/../examples')); var future2 = galaxy.spin(countLines(__dirname + '/../lib')); var future3 = galaxy.spin(countLines(__dirname + '/../test')); var total = (yield future1()) + (yield future2()) + (yield future3()); console.log('TOTAL: ' + total); return total; }These future's that galaxy uses are in fact abstractions around an asynchronous process, just like promises.The only difference being that they are only useful inside galaxy and they do not conform to a standard, and they require you to use a special wrapper function (spin).
It doesn't seem like a good idea to me that you would have to rewrite the way you call a function in order to affect parallelism.With promises you ether yield, or don't, and keep the promises for reference. No need for a special spin function.
( The requirement to call a future when yielding it seems somewhat cumbersome to.)This proves pretty clearly that you need some sort of an abstraction.
If you want an annotation, just add a comment.You can't really efficiently say in a comment that the generator is in fact a coroutine that requires an invoke trough a specific library.A regular coroutine should be just a function, like any other async operation should be.
Regarding performance, function wrappers are not always static...True, but let's not drag in actual performance in the discussion. We need benchmarks to make any sort of point around them and I think the discussion is more about api design then what V8 is capable of optimizing.It is the de facto standard in the node.js ecosystem. And it is more efficient!de facto != de jure, that's my point, standardization is good, it allows for a more stable ecosystem.
The fact that you have to unstar a function that comes from galaxy if i want to do an invocation from outside the library seems very uncanny.It's bad enough we have to wrap the core api's for coroutine management, now we have to wrap functions from the library that tries to solve that as well, It's only adding to the problem.
// async
If your APIs return promises, you'll need to provide wrappers to transform both ways between promises and callback-based APIs.
I'm using streamline which works directly with node.js callbacks.
--
// asyncI think that is very verbose, It will not be very helpful to someone who doesn't know galaxy well or even does know coroutines. ( is it a coroutine, is it a generator ? its both ! )
If your APIs return promises, you'll need to provide wrappers to transform both ways between promises and callback-based APIs.Bruno, that is simply not true. If a library returns promises u can just use the promise. You will always need to write more code to convert a promise to a callback style function then to just use the promise.
I'm using streamline which works directly with node.js callbacks.Streamline.js also provides "futures", also by using a special syntax. !_( which is also noise imo )
So if you use both libs, you are using two different type of control flow libraries ( of which one is a pre-processor ) , that both allow you to create async encapsulations with special syntaxes, to workaround callbacks.
I think I will just stick to promises.I can't help but feel that they are more uniform, cleaner and how ECMAScript is intending async control flow in the future.
I think I will just stick to promises.I can't help but feel that they are more uniform, cleaner and how ECMAScript is intending async control flow in the future.
I did not jump in to convince you to use galaxy or streamline (I got bored with this kind of exercise), rather to develop Alex' point that "you *can* have coroutines without promises". Promises don't really cut it when it comes to solving the "sync-style coding" challenge. What cuts it is generators (fibers and preprocessors too).
Exactly: Promises give you something else, without being ‘sync’-style. They let you manipulate as-yet-unavailable values relatively transparently. Actual order of operations can be factored out instead of made explicit; what’s left is order of dependency, rather than order of operations.
So at work we're working on a bunch of node modules that will eventually be published as open-source and I'm in favor of callbacks and two of my co-workers are in favor of promises. We've discussed supporting both API interfaces and I was curious what the general consensus of the community was with respect to supporting both and the best way to name functions and methods to support both.That being said, there are three obvious choices:(a) two function types: (1) synchronous functions; and (2) async functions that return promises but also handle callbacks
(b) three function types: (1) synchronous functions; (2) async callback functions; and (3) async promise functions
(c) two function types: (1) synchronous functions; (2) async callback functions;