Hi Jeremy,
I had completely missed the fact that you are wrapping every generator
function that you write with a `suspend` call. So I concluded too quickly
that your implementation was rather naive. But it's not and it's actually
very clever because it does a lot with very little code (16 lines only vs.
159 for galaxy).
As you say galaxy takes a different approach. My goal was to obtain the
leanest code possible when writing galaxy code that calls other galaxy code
and I was happy because I managed to get 0% fat: galaxy code that calls
other galaxy code is just as lean as JS that calls JS if JS had async/await
keywords: async = * and await = yield. There is no galaxy API in the middle
(except for parallelizing). The galaxy functions are just used at both ends
of the call stack: `star` when you call low level node APIs and `unstar`
when your functions are called by node.
Note that you don't need to shim entire modules to call them, you can shim
individual functions. For example:
var fs = require('fs');
var star = require('galaxy').star;
function* countLines() {
var contents = yield star(fs.readFile)(__filename, 'utf8');
return contents.split('\n').length;
}
I feel that the two approaches are rather complementary:
- Suspend seems most appropriate for libraries: you don't have to shim
node.js calls and the APIs that you create are directly exposed as node
callback APIs.
- Galaxy is more targetted at applications: most of the code that you
write calls your own APIs and galaxy is the leanest and least intrusive in
this case.
Bruno
On Friday, May 31, 2013 5:48:53 PM UTC+2, jmar777 wrote:
>
> Bruno -
>
> After looking over galaxy for a bit, I'd say suspend and galaxy's
> philosophies are pretty different.
>
> That is, suspend's API is designed to work *directly* with node's
> callback conventions (where `resume` acts as the continuation), whereas *
> galaxy's* API allows you to *wrap* code that uses node's callback
> conventions (using `galaxy.star()`).
>
> For example, in galaxy, the `galaxy.star()` method does the API conversion
> in convertAPI():
>
> return Object.keys(api).reduce(function(result, key) {
> var fn = api[key];
> result[key] = (typeof fn === 'function' && !/Sync$/.test(fn.name))
> ? converter(fn, idx) : fn;
> return result;
> }, {});
>
> It appears, then, that in order to use galaxy.js with existing code, you
> need a shim between it and galaxy. This shim makes some assumptions, such
> as whether or not `Sync` is in the name. So, would this convention need to
> be followed by user-land modules as well to work with galaxy? Also, it
> seems to only convert top-level exports. You'll have to weigh between the
> performance tradeoffs there, but I've seen modules that namespace the
> functionality, which would appear to thwart convertAPI() at the moment.
> Anyway, still digging through the source - it's interesting, but apart
> from the use of generators, it looks like suspend and galaxy are a bit like
> apples and oranges.
>
> On Fri, May 31, 2013 at 10:12 AM, Jeremy Martin <[email protected]<javascript:>
> > wrote:
>
>> Not sure I follow what you mean by "one yield per function". The
>> following works, if that's what you mean:
>>
>> var suspend = require('./'),
>> fs = require('fs');
>>
>> suspend(function* (resume) {
>> // read the current file
>> var res = yield fs.readFile(__filename, { encoding: 'utf8' },
>> resume);
>> // replace tabs with spaces
>> var newContents = res[1].replace(/\t/g, ' ');
>> // write back changes
>> yield fs.writeFile(__filename, newContents, resume);
>> // print modified file
>> var modified = yield fs.readFile(__filename, { encoding: 'utf8'},
>> resume);
>> console.log(modified[1]);
>> })();
>>
>> This performs 3 asynchronous operations within the same generator.
>> Nothing prohibits nesting, either (again, not entirely sure what you mean,
>> but the following works as well):
>>
>> var suspend = require('./'),
>> fs = require('fs');
>>
>> var readCurrentFile = suspend(function* (resume, cb) {
>> var res = yield fs.readFile(__filename, { encoding: 'utf8'},
>> resume);
>> cb(null, res[1]);
>> });
>>
>> var writeToCurrentFile = suspend(function* (resume, data, cb) {
>> yield fs.writeFile(__filename, data, resume);
>> cb(null);
>> });
>>
>> suspend(function* (resume) {
>> var res = yield readCurrentFile(resume);
>> var newContents = res[1].replace(/\t/g, ' ');
>> yield writeToCurrentFile(newContents, resume);
>> var modified = yield readCurrentFile(resume);
>> console.log(modified[1]);
>> })();
>>
>> Congrats on getting galaxy out, looking it over now! Curious about the
>> fanciness you had to include in the `run` function.
>>
>> On Fri, May 31, 2013 at 2:56 AM, Bruno Jouhier
>> <[email protected]<javascript:>
>> > wrote:
>>
>>> Look like your start function only handles one yield per function. What
>>> if you want to make several async calls from the same function? How do you
>>> handle several levels of async calls (async f1 calling async f2 calling
>>> async f3)?
>>>
>>> I just published a module that handles these cases (
>>> https://github.com/bjouhier/galaxy) but I had to use a much trickier
>>> `run` function for this.
>>>
>>> Bruno
>>>
>>>
>>> On Tuesday, May 28, 2013 4:20:06 PM UTC+2, jmar777 wrote:
>>>>
>>>> *suspend* <https://github.com/jmar777/suspend> is a new control flow
>>>> library that exposes a minimal API around* ES6 generators*, and is
>>>> expressly designed to work transparently with Node's existing callback
>>>> conventions. This allows unobtrusive use of *yield* execution
>>>> semantics that works seamlessly with existing Node code bases (no need to
>>>> wrap everything in a promises/whatever layer).
>>>>
>>>> *Quick example:*
>>>> *
>>>> *
>>>> var suspend = require('suspend'),
>>>> fs = require('fs');
>>>>
>>>> suspend(function* (resume) {
>>>> var data = yield fs.readFile(__filename, resume);
>>>> console.log(data[1].toString('**utf8'));
>>>> })();
>>>>
>>>> *Links:* GitHub Repo <https://github.com/jmar777/suspend> | Blog
>>>> Announcement<http://devsmash.com/blog/suspend-generator-based-control-flow-for-node>
>>>>
>>>> *NPM: *$ npm install suspend
>>>>
>>>> *suspend* is extremely experimental, and I would greatly appreciate
>>>> any feedback!
>>>>
>>> --
>>> --
>>> 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 [email protected]<javascript:>
>>> To unsubscribe from this group, send email to
>>> [email protected] <javascript:>
>>> 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/jfOq8mpaqss/unsubscribe?hl=en.
>>> To unsubscribe from this group and all its topics, send an email to
>>> [email protected] <javascript:>.
>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>
>>>
>>>
>>
>>
>>
>> --
>> Jeremy Martin
>> 661.312.3853
>> http://devsmash.com
>> @jmar777
>>
>
>
>
> --
> Jeremy Martin
> 661.312.3853
> http://devsmash.com
> @jmar777
>
--
--
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 [email protected]
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/groups/opt_out.