asyncblock 1.0 released (Flow control library built on Fibers)

272 views
Skip to first unread message

Chris Scribner

unread,
Dec 31, 2011, 9:55:00 PM12/31/11
to nodejs
Dear community,

I've been hard at work on asyncblock, a library aimed at exposing the
power of fibers in a simple to control manner. Some highlights:

* Write async code in synchronous style without blocking the event
loop.
* Effortlessly combine serial and parallel operations with minimal
boilerplate.
* Simplify error handling by passing errors to your callback, no
matter how they arose.
* Improve debugging by keeping more of the stack trace, automatically.
* Support for task timeouts, maximum parallel task concurrency, and
other advanced features.
* No pre-compilation required. The code you write is the code that
runs.
* No prototypes were harmed in the making of this module.

The module:
https://github.com/scriby/asyncblock

Heavy lifting provided by:
https://github.com/laverdet/node-fibers

Thanks!

Feedback is welcome,

Chris

Glenn Block

unread,
Dec 31, 2011, 10:09:57 PM12/31/11
to Chris Scribner, nodejs
Nice!

Sent from my Windows Phone
From: Chris Scribner
Sent: 12/31/2011 6:55 PM
To: nodejs
Subject: [nodejs] asyncblock 1.0 released (Flow control library built
on Fibers)
Dear community,

The module:
https://github.com/scriby/asyncblock

Thanks!

Feedback is welcome,

Chris

--
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

Dobes

unread,
Jan 1, 2012, 6:48:04 AM1/1/12
to nodejs
Looks nice.

I noticed that for wait() you say "If there is only one call to
flow.add and no key is passed, the result will be returned as is
without the object wrapper." I think may be an error-prone approach,
as it means if you edit some code you might change the return value of
wait() unintentionally by adding or removing a call to add(). Then
you'll have to change how you handle the return value of wait() after
making edits. I think the system would be more robust against
programmer errors if wait() were predictable in its return value,
containing only the results of callbacks that were given a key, and
never just a single object unless you passed a key to wait for.

Perhaps instead you could have methods waitNext() or waitLatest()
which returns the single value of the next pending or most recently
added callback (basically equivalent to calling wait() with the key of
the callback, had it been given one).

Another similar case is the actual value(s) returned from wait(). It
says that "When more than one parameter is passed from an asynchronous
function's callback, it is converted to an array". This troubles me
because there may be cases where a callback is invoked with one or
more than one parameter depending on the situation, or even the
version of the library being used. I could see some library I am
using adding a bonus parameter later on that wasn't present when I
first wrote my code, and now that value is turned into an array by
asyncblock instead of a single value. Probably a more rare case but
still worth considering IMO. Having a very consistent return value
will avoid future bugs for people. I'd suggest something like "The
first parameter to the callback is always the error. The second is
the value returned by wait(). Additional parameters are accessible by
another mechanism...". The mechanism for accessing the other
arguments might be to have methods on the return value from wait, such
as getAllArguments(key) to return the full array of arguments after
the first "error" argument.

Some things to consider!

Warm Regards,

Dobes

Oleg Podsechin

unread,
Jan 1, 2012, 12:56:28 PM1/1/12
to nod...@googlegroups.com
This looks very useful for mixing synchronous and asynchronous programming styles in one application. However, something I've found in my own projects is that the code across an entire application tends to be either all sync or all async. 

As a result, for sync stuff I use my higher level abstraction library called Common Node (http://olegp.github.com/common-node/ - it also uses fibers), which lets you program in a completely synchronous manner at a higher level of abstraction. With Common Node's higher level abstraction you don't need to deal with the individual events that Node exposes when doing something like an HTTP request, but rather simply call a function and use its return value. 

For async stuff, like writing a load balancer, I tend to go with pure Node, without any flow control libraries, since I want to keep the code as simple as possible to make it easier to debug.

Have other people writing both sync and async code noticed this as well or are you happy to combine different styles in one application?

Oleg


Chris Scribner

unread,
Jan 1, 2012, 4:20:38 PM1/1/12
to nodejs
Thanks for your thoughtful comments.

1. I agree there's a potential for errors here, but I'm not sure
there's a good middle ground. A waitLast() function would still break
in cases where another add was placed after the existing add as we'd
be waiting on the wrong thing. I could imagine a waitOne function that
waits for exactly one task, and if more than one task was outstanding,
it would throw an Error. But that still boils down to a runtime error.
The most robust solution is to provide a key in the add and wait
calls, which is already possible (or use flow.sync). So, I'm not sure
if it's worth adding another way to do this. I could add a note of
caution about the potential problem by using add and wait in the way
you described.

2. This is a very good consideration. I don't think I can implement it
in the exact way you suggested, as I wouldn't know when to purge
return values that were never retrieved. On my work mac, asyncblock
can do about 100,000 add / waits in 1 second, so the garbage could
build up fast. I think a good solution to this problem is to always
have wait just return the second return value unless a responseFormat
is provided. This breaks backwards compatibility, but it's best to do
so now before people rely on the array syntax (which is really just
being lazy -- using a responseFormat is more readable).

Chris

Dobes

unread,
Jan 2, 2012, 10:59:02 PM1/2/12
to nodejs
For #1, you are right that is a good point. Discouraging the use of
unnamed return values in the docs is probably sufficient. You could
also document what happens to the return value of wait() if you have
multiple calls to add() of which some or all have no key.

For #2, also sounds good. However I do wonder - how do you know when
to purge the return values currently?

Also it occurred to me that you could allow someone to pass the
special value Array as the responseFormat if they wanted to get an
array of arguments instead of a map. This might be useful if they are
expecting a variable number of arguments back. Not necessarily
something you see in real code, though, so maybe not a terribly useful
idea in the real world.

Cheers,

Dobes

Jeffrey Zhao

unread,
Jan 3, 2012, 4:19:40 AM1/3/12
to nod...@googlegroups.com
I always feel it’s much easier to express the logic in sync style than async. So in most cases I’ll use sync style to express my logic and hook up with async code when necessary.
 
Jeffrey Zhao
Blog: http://blog.zhaojie.me/
Twitter: @jeffz_cn (Chinese) | @jeffz_en (English)

Chris Scribner

unread,
Jan 4, 2012, 9:31:33 AM1/4/12
to nodejs
2. asyncblock purges return values as soon as the user requests them.
So flow.wait will purge (and return) all stored return values, and
flow.wait(key) will purge (and return) just that one return value.

Chris

Axel Kittenberger

unread,
Jan 4, 2012, 10:10:21 AM1/4/12
to nod...@googlegroups.com
Great work!

I wonder if it would be possible to combine call and wait into a
single line for the simple case, so to be more like streamline. In my
humble opinion this might improve popularity of such module like:

var asw = flow(setTimeout(flow.callback(), 2000));
var parallel = flow(setTimeout(flow.callback(), 2000),
setTimeout(flow.callback(), 3000));

Chris Scribner

unread,
Jan 4, 2012, 12:17:46 PM1/4/12
to nodejs
I'm not sure all those syntaxes are possible. I tried to do something
like

setTimeout(flow.addAndWait(), 3000);

But it's not possible because the addAndWait call needs to yield the
current fiber. If it yields before returning, the setTimeout call will
never be made. It can't yield after returning, b/c the yield has to be
done from the fiber (can't happen from a nextTick).

setTimeout is actually a bad example, because it doesn't follow normal
async style of function(..., callback).

There are some one-liners available for normal async style functions,
like this:

var sleep = function(delay, callback){
setTimeout(callback, delay);
};

var fs = asyncblock.wrap(require('fs')); //Create a async -> sync
wrapper that lets you use one-liners later on

asyncblock(function(flow){
// Sleeps for 1 second before continuing.
var result = flow.sync(sleep, 1000);

//One-liner to grab file contents, using a wrapped object
var fileContents = fs.sync.readFile(path, 'utf8');
});

The example "var asw = flow(setTimeout(flow.callback(), 2000));" is
interesting. I think it would look something like this:

asyncblock(function(flow){
var asw = flow.waitOne(asyncFunc(arg1, arg2, flow.callback())); //
waitOne waits on the last added task and returns the result
});

I'm not 100% sure it's worth it to add that syntax, in that it might
add confusion for people trying to learn the API. What do you think?
Would you want to use something like that instead of the other
methods?

Thanks,

Chris

Chris Scribner

unread,
Jan 7, 2012, 11:08:54 PM1/7/12
to nodejs
I thought about this for a bit and added a chained style syntax to
allow more succinct code in some cases:

asyncblock(function(flow){
//Get the result of fs.readFile(path, 'utf8')
var contents = flow.func(fs.readFile).args(path, 'utf8').sync();

//Read two files in parallel, then wait on writing the combined
contents
var f1 = flow.func(fs.readFile).args(path1, 'utf8').future();
var f2 = flow.func(fs.readFile).args(path2, 'utf8').future();
flow.func(fs.writeFile).args(path3, 'utf8', f1.result +
f2.result).sync();
});

There's a couple more chaining functions that allow additional options
to be set, and the specifying of the "this" context for the function
call.

Thanks,

Chris

Alan Hoffmeister

unread,
Jan 8, 2012, 1:41:04 PM1/8/12
to nod...@googlegroups.com
Awesome!
--
Att,
Alan Hoffmeister

Axel Kittenberger

unread,
Jan 8, 2012, 1:58:31 PM1/8/12
to nod...@googlegroups.com
Going to explore some cool possibilities! :-)

>    //Get the result of fs.readFile(path, 'utf8')
>    var contents = flow.func(fs.readFile).args(path, 'utf8').sync();

Is the this pointer in readFile correct and equal to fs?

Chris Scribner

unread,
Jan 8, 2012, 6:58:33 PM1/8/12
to nodejs
The this pointer will not be "correct", but note that it doesn't
matter for the fs module.

Here's an example where it matters:

var obj = {
append: 'test',

echo: function(message, callback){
process.nextTick(function(){
callback(null, message + this.append);
});
}
};

asyncblock(function(flow){
var wrapped = asyncblock.wrap(obj);

var message = flow.func(obj.echo).self(obj).args('hi, ').sync();
//message is "hi, test"

//You can also do it like this:
message = flow.func('echo').self(obj).args('hi, ').sync();
});

Chris

Marcel Laverdet

unread,
Jan 8, 2012, 10:25:20 PM1/8/12
to nod...@googlegroups.com
What is the advantage of the chaining syntax over something like:

func(obj.echo).call(obj, 'hi, ')

or

func(fs.readFile)('./info.txt')

Chris Scribner

unread,
Jan 8, 2012, 11:23:52 PM1/8/12
to nodejs
I liked the chaining syntax because it gives a lot of flexibility. I
can implement call / apply with it easily, too. But the main reason
for it was to give a place to add options like timeouts and whatnot.

I have been thinking about doing the 2nd syntax as well. It looks like
an ok shorthand, but wasn't sure it's really any better than the
existing flow.sync. I'm all for more choices, but I wonder if I'm
getting to the point where people will have a hard time sifting
through it all to figure out which call to use.

Thoughts?

Thanks,

Chris

Marcel Laverdet

unread,
Jan 9, 2012, 1:13:04 AM1/9/12
to nod...@googlegroups.com
Well I wasn't saying you should implement call and apply yourself, I was just saying it seems like flow.func() should just return a function (see my second example in the last email). Implementing function calls in a chaining pattern seems annoying because you have to totally deconstruct what is normally simple JS.

The way I do this with my futures library is I have a future that will just throw after a given timeout:

new TimeoutFuture(1000).wait(); // throws after 1s

Then you have another future which will take N futures and pass through whichever one finishes first. You combine these two and you have your blocks that throw if it took too long:

try {
  var val = new RaceFuture(new WhateverFuture(), new TimeoutFuture(1000)).wait();
  console.log('WhateverFuture returned successfully: '+ val);
} catch (err) {
  console.log('Timeout, or other failure');
}

It sounds kind of cumbersome but it's not really a pattern that comes up enough in my application. If it were super common I'd wrap that up into some utility function. I'm not sure if that's what's best for your library, but it works well for me.

Chris Scribner

unread,
Jan 9, 2012, 8:37:21 AM1/9/12
to nodejs
Well, the good news is that func can return a function without
breaking reverse compatability with what I've already got. I wanted to
make sure the 2nd syntax would still be possible to implement.

So stuff like this would be possible:

asynblock(function(flow){
var contents = flow.func(fs.readfile)(path, 'utf8');

contents = flow.func(fs.readfile).options({ timeout: 1000 })(path,
'UTF8');

var result = flow.func(obj.echo).options(...).call(obj, message);
});

That's what I meant by the chaining syntax being really flexible. And
if you don't want to get the result immediately, you can end the chain
with .queue() or .fututre().

I'll work on it soon. Looks useful, and fun to work on.

Chris

Chris Scribner

unread,
Jan 9, 2012, 9:14:43 PM1/9/12
to nodejs
I implemented the syntax you're talking about and pushed it in v1.5.0.
I think it turned out well and offers some good syntactic sugar.

Thanks for the input,

Chris

On Jan 9, 1:13 am, Marcel Laverdet <mar...@laverdet.com> wrote:

Axel Kittenberger

unread,
Jan 10, 2012, 4:00:18 AM1/10/12
to nod...@googlegroups.com
Great, I'm sorry to thrust down more ideas, but I gave just some more
thought about this.

I think in an ideal world, you would never have to call some sort of
wait() anywhere. You would have some way of dependency analysis that
decides for you, what things can run in parallel, without having to
explicitly write it out yourself. Of course the good coder, still
needs to write code that way, to give that flow diagram good
possibilities to do things in parallel.

But maybe thats kind of possible. So you call the async function, and
it returns a future/promise kind of object, which halts execution just
when you need its value and its not there yet. Might even be possible
to do by Javascripts valueOf feature.

var o = flow(some.aSyncFunction(foo, bar, flow.callback)) // <-- this
returns an object whouse valueOf function is set. Returns immediately.
var x = o + 1; <-- the valueOf function will yield when o is not yet ready.

Maybe this will let people scream up again yet once more, because of
the hazards to do unsafe use of globals and not caring when the yield
might happen. Maybe it still is a nice option for efficient and
elegant coding for people who just avoid coding that kind of hazards.

Marcel Laverdet

unread,
Jan 10, 2012, 5:18:43 AM1/10/12
to nod...@googlegroups.com
@axel I've alluded to a theoretical library of that sort and would be absolutely thrilled to see someone build it.

Chris Scribner

unread,
Jan 10, 2012, 8:25:11 AM1/10/12
to nodejs
This is already possible with asyncblock. It's also possible with node-
sync's futures.

Read up about flow.wait(key) or using futures. Here's some examples:

asyncblock(function(flow){
fs.readFile(path1, 'utf8', flow.add(1));
fs.readFile(path2, 'utf8', flow.add('b'));

...
//Yield here until task 1 is done
var contents1 = flow.wait(1);

//Yield here until task b is done
var contents2 = flow.wait('b');

//or with futures
var future = flow.func(fs.readFile).args(path, 'utf8').future();

...
//yield here until the result is ready
var contents3 = future.result;

//using a wrapped object
fs = asyncblock.wrap(fs);
var future2 = fs.future.readFile(path, 'utf8');

...
//Yield here until result is ready
future2.result;

//This syntax is not supported, but could be:
var future;
fs.readFile(path, 'utf8', future = flow.future());
});

Thoughts?

Chris

Chris Scribner

unread,
Jan 10, 2012, 9:02:09 AM1/10/12
to nodejs
I may have missed the point of your post. Was it important that
valueOf is used to make the syntax clean, or just that it's possible
to get the result "on demand"?

I can definitely play with using valueOf on futures to see if that
syntax is possible.

Thanks,

Chris

Axel Kittenberger

unread,
Jan 10, 2012, 9:12:35 AM1/10/12
to nod...@googlegroups.com
Its about getting a concise syntax that feels "natural", IMHO
everything we did so far, was just a tad too verbose/clunky to feel
really going well in everyday work.

One idea state would be to have all the asny/parallell tasks quite in
the background, like this:

var contents1 = fs.readFile(path1, 'utf8');
var contents2 = fs.readFile(path1, 'utf8');
console.log(content1 + '::' content2);

One might argue, that in this state its too obscure, where
halt/reentries might happen, and this is evil. In that case where
content1 and content are computed.

Following might be a good compromise:

var contents1 = async(fs.readFile(path1, 'utf8', callback));var
contents2 = async(fs.readFile(path1, 'utf8',
callback));console.log(contents1.keep + '::' contents2.keep);

async highlights there is something happening otherwise, "keep" (like
keeping the promise) is a getter, that might yield the until the async
is completed if it didn't already. Any calls to keep would be possible
reentry points. The hazard of random subroutines yielding on you,
without expectation is removed, since only who holds the "async"
handler, can create new promise/keep objects. And only who holds such
a value, is able to call its .keep getter, so a yield might happen.

Axel Kittenberger

unread,
Jan 10, 2012, 9:14:10 AM1/10/12
to nod...@googlegroups.com
That came a little mixed up:

Axel Kittenberger

unread,
Jan 10, 2012, 9:43:19 AM1/10/12
to nod...@googlegroups.com
The problem I see we're dancing around is fundamental entailed with
javascript, I do not know a satisfying workaround.

Either the actual call to the async function is made in the main
application. This forces the application coder to make some more info
to the callback, so callback and async are matched (this is what you
first have done). This creates a heavy API to take care of, to do it
correctly.

Or you make the library do the actual function call, so it can fill
the callback parameter itself (this is what you second add-on did).
This, however, mangles up the this pointer and is thus bad. Having to
supply the this pointer as well, makes the whole interface cumbersome
again.

Third option is a complete preprocessor, like streamline did, which is
perceived a tad hefty by people, and the code you debug is not 100%
anymore the code you write.

Non of the three options is really, really satisfactory IMHO.

Chris Scribner

unread,
Jan 10, 2012, 10:26:43 AM1/10/12
to nodejs
I hope we can agree that this syntax is not possible, as it's not
possible to "return a getter":

var contents1 = fs.readFile(path1, 'utf8');
var contents2 = fs.readFile(path1, 'utf8');
console.log(content1 + '::' content2);

This syntax isn't exactly possible, but it's similar to stuff you can
already do:

var contents1 = async(fs.readFile(path1, 'utf8', callback));
var contents2 = async(fs.readFile(path1, 'utf8', callback));
console.log(contents1.keep + '::' contents2.keep);

Like this (which is even less verbose):

fs.readFile(path1, 'utf8', flow.add(1));
fs.readFile(path2, 'utf8', flow.add(2));
console.log(flow.wait(1) + '::' + flow.wait(2));

Or,

fs = asyncblock.wrap(fs);
var contents1 = fs.future.readFile(path1, 'utf8');
var conents2 = fs.future.readFile(path2, 'utf8');
console.log(contents1.result + '::' + contents2.result);

Or, I could even make flow.func,future a little less verbose, like
this:

var contents1 = flow.func(fs.readFile).future(path1, 'utf8');
var contents2 = flow.func(fs.readFile).future(path2, 'utf8');
console.log(contents1.result + '::' + contents2.result);

But it looks like the closest I could come to your exact preferred
syntax would be one of these examples;

var contents1, contents2;
fs.readFile(path1, 'utf8', contents1 = flow.future());
fs.readFile(path2, 'utf8', contents2 = flow.future());
console.log(contents1.result + '::' + contents2.result);

Or,

var contents1 = flow.future(fs.readFile(path1, 'utf8', flow.add());
var contents2 = flow.future(fs.readFile(path2, 'utf8', flow.add());
console.log(contents1.result + '::' + contents2.result);

Or even this (which could bind getters to the local scope),

fs.readFile(path1, 'utf8', flow.bind(this, 'contents1'));
fs.readFile(path2, 'utf8', flow.bind(this, 'contents2'));
console.log(contents1 + '::' + contents2);

What's your preference out of those possibilities? My personal
preference is towards the syntax already available (but that makes
sense because I designed it :).

Also, I looked into valueOf, but I don't think it looks like a safe
approach. Because it only gets called when the value is used like a
primitive, the behavior could be pretty erratic based on the usage of
the variable.

Thanks,

Chris

Chris Scribner

unread,
Jan 10, 2012, 10:33:00 AM1/10/12
to nodejs
We're using asyncblock in an internal project and I find it a joy to
use compared to other flow control solutions.

That's good enough for me. Reaching theoretical perfection is outside
the scope of javascript :) And of course there are other languages
with different models, if that's really important to you.

I appreciate your input. It spurs some good conversation and increases
the utility of asyncblock.

Thanks,

Chris

Mark Hahn

unread,
Jan 10, 2012, 2:24:51 PM1/10/12
to nod...@googlegroups.com
What's your preference out of those possibilities? 

Thanks for the great summary of alternatives.  It opened up my mind.  I've had my mind closed for some time about pseudo-sync coding tools.  Things got too muddled, even (or especially) after writing my own.

I particularly like ...

    fs.readFile(path1, 'utf8', flow.add(1));
    fs.readFile(path2, 'utf8', flow.add(2));
    console.log(flow.wait(1) + '::' + flow.wait(2));

But I would prefer flow.set and flow.get over flow.add and flow.wait. I think it is simpler to think of a setter/getter which is data-oriented instead of add/wait which is flow-oriented.

It could be as easy as 

    fs.readFile(path1, 'utf8', _set(1));
    fs.readFile(path2, 'utf8', _set(2));
    console.log(_get(1) + '::' + _get(2));

Is there any tool that already comes close to this?


Chris Scribner

unread,
Jan 10, 2012, 4:54:39 PM1/10/12
to nodejs
I don't mind the idea of implementing a flow.set & flow.get. The one
tricky part is garbage collection.

When using flow.add / flow.wait, the results get cleared out as soon
as they're returned to the caller. With the get / set metaphor, it
seems expected that you could get the same key more than once (the
first time it yields, the 2nd time it just returns the cached result).

Things will still be garbage collected when the asyncblock ends, but
it wouldn't be appropriate for long running blocks that need the
results to be garbage collected sooner.

Thanks,

Chris

Mark Hahn

unread,
Jan 10, 2012, 5:01:04 PM1/10/12
to nod...@googlegroups.com
Maybe a flow.del?

Chris Scribner

unread,
Jan 10, 2012, 10:24:28 PM1/10/12
to nodejs
I added the flow.get & flow.set paradigm to asyncblock and pushed to
npm. Check it out and let me know what you think.

I also put together an overview (https://github.com/scriby/asyncblock/
blob/master/docs/overview.md) which presents each way of using
asyncblock in a simple format. Hopefully that will help learn the
features of the library more easily.

Thanks,

Chris

Dobes

unread,
Jan 10, 2012, 10:41:40 PM1/10/12
to nodejs
I think the problem with syntax like "func(fs.readFile)('./info.txt')"
is that it starts to become pretty obscure for someone new to the
code.

At least if there's a method name it gives you a hint and something to
grep for.

Hopefully all this fibers stuff will be integrated into the node core
sometime so I can use it, currently I'm using Windows so c++
extensions are painful to use.

Dobes

unread,
Jan 10, 2012, 10:47:34 PM1/10/12
to nodejs
I think he was talking about some kind of "lazy value" where you can
use the return value of the function as if it were returned
synchronously and it waits automatically for the async call to
complete when the value is actually used for the first time.

My past experience with "magic" of this kind is that it's nice for
writing (less) code, but confusing when reading and debugging code
because there's more happening behind the scenes that you might not
know of or easily forget about. You might expect from reading the
code that exceptions will be thrown when the initial call is made but
in this scenario the exception would be thrown when the value is used
for the first time instead.

So, I think the way things are currently where the waiting is done
explicitly does mean more code, but easier to understand and debug
code.

Mark Hahn

unread,
Jan 10, 2012, 11:28:18 PM1/10/12
to nod...@googlegroups.com
Looks like a flexible set of solutions.  I'll have to try it out.

Marcel Laverdet

unread,
Jan 11, 2012, 12:14:20 AM1/11/12
to nod...@googlegroups.com
> I think the problem with syntax like "func(fs.readFile)('./info.txt')"
> is that it starts to become pretty obscure for someone new to the
> code.

The idea is that you would do:
var readFile = func(fs.readFile);

And then just call readFile() like a normal function.

> Hopefully all this fibers stuff will be integrated into the node core
> sometime so I can use it

Shhh we don't say those words around here. You'll awaken the elders.

Axel Kittenberger

unread,
Jan 11, 2012, 1:16:24 AM1/11/12
to nod...@googlegroups.com
This is IMHO quite a nice construction once I thought about it:

> var contents1, contents2;
> fs.readFile(path1, 'utf8', contents1 = flow.future());
> fs.readFile(path2, 'utf8', contents2 = flow.future());
> console.log(contents1.result + '::' + contents2.result);

Depending on style, one might also write like this with same mechanics:

var contents1 = future(), contents2 = future();
fs.readFile(path1, 'utf8', contents1);
fs.readFile(path2, 'utf8', contents2);
console.log(contents1.value + '::' + contents2.value);

Axel Kittenberger

unread,
Jan 11, 2012, 8:08:45 AM1/11/12
to nod...@googlegroups.com
BTW. since I got it popping up again and again, I googled and didn't
find a suitable simple explanation.

Can somebody explain me what a "future" and "promise" actually is in
detail? Whats the difference between the both? "? I know what a
callback is, and what a fiber is. I get it futures and promises are
both some kind of function returned, but what exactly is know a
"future" and a "promise". And the difference between the both. I so
far just used node-futures etc. but it was more a general flow-control
library to me.

Marcel Laverdet

unread,
Jan 11, 2012, 2:16:12 PM1/11/12
to nod...@googlegroups.com
Promises and futures as used by the Node community are essentially interchangeable. I believe classically what we are using are called promises. That is, the objects returned have an explicit method to resolve the returned payload. On the other hand, futures would be a reference to an object that hasn't been returned yet. Futures would be closer to the valueOf() hack you were talking about earlier, where the future magically becomes the object that was returned.

I'm not sure if this is totally accurate, but it's my understanding of the situation.

Chris Scribner

unread,
Jan 14, 2012, 3:42:39 PM1/14/12
to nodejs
Just an FYI... I added a few new options to asyncblock (1.7.0) just
now, based on this discussion:

asyncblock(function(flow) {
//A new one-liner construction
var contents = flow.sync( fs.readFile(path, 'utf8',
flow.callback()) );

///Futures
var future = flow.future();
fs.readFile(path, 'utf8', future);
var contents = future.result;

//Or, like this
var future = flow.future( fs.readFile(path, 'utf8',
flow.callback()) );
var contents = future.result;

//The above examples are equivalent to these
fs.readFile(path, 'utf8', flow.set('contents'));
var contents = flow.get('contents');

fs.readFile(path, 'utf8', flow.add());
var contents = flow.wait();
});

Thanks,

Chris
Reply all
Reply to author
Forward
0 new messages