Graduating the new async primitives from Closure Labs (Result, chain, combine, transform)

1,074 views
Skip to first unread message

Vipul Bhasin

unread,
Jun 20, 2012, 8:26:04 PM6/20/12
to closure-lib...@googlegroups.com
Hello Closure Users,

The Closure team is in the final stages of graduating the new asynchronous primitives (Result, chain, transform, combine) from labs to the core library and wanted to ask for any comments you might have on their syntax, naming or usage. These primitives are developed to offer a simpler way to do asynchronous communication and replace the currently used Deferred's.

Following are the current outstanding issues:

1) Syntax
Short snippets of usage are presented below. There are more examples in the file headers : http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/labs/async/ and also in goog.labs.net.xhr (http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/labs/net/xhr.js), which now uses the new primitives.

Usage of wait :

var result = xhr.get('data.url');
goog.concurrent.wait.onSuccess(result, function(result) {
  var value = result.getValue();
  alert("Value: " value);
});
// There is also onError used to attach handlers when the result errors.
// result.getError() is used to retrieve the error value.

Usage of chain (a chain of results resolved in order : intended to be used for serial operations) :

var result1 = xhr.get('some.data.url');
var chainedResult = goog.concurrent.chain(result1, function(result) {
    var secondUrl = result.getValue();
    var result2 = xhr.get(secondUrl);
    return result2;
});
// Use wait methods to wait on the chainedResult.
// chainedResult.getValue() returns the value of result2 on success.
// chainedResult resolves to an error when any result in the chain is an error.
Usage of combine (resolves when all results are resolved : intended to be used for parallel operations) :

var result1 = xhr.get('some.data');
var result2 = xhr.get('some.more.data');
var combinedResult = goog.concurrent.combine(result1, result2);

// Use wait methods to wait on the combinedResult which resolves when both result1 result2 are resolved.
// combinedResult errors when either is an error.

Usage of transform (for processing data of an operation before using it; strip prefixes, parse JSON, etc) :

var transformer = function(resultValue) { return resultValue * 2; }

var result = xhr.get('some.data');
var transformedResult = goog.concurrent.transform(result, transformer);

// The value of transformedResult is the value returned by the transformer
// The transformer is not called if the result is an error.


2) Namespace for the new primitives:
The current proposal is to move them from goog.labs.async to goog.concurrent (goog.concurrent.Result, goog.concurrent.wait, etc) since goog.async already has (unrelated) primitives for delay, animation, throttle, and the like.

3) Naming of the object:
Currently the objects are called Results. Other proposed names are : Promises, Futures.

Please let us know if you have any comments, questions, or concerns.

Thanks,
Vipul

GordonHo

unread,
Jun 21, 2012, 4:51:42 AM6/21/12
to closure-lib...@googlegroups.com
thanks a lot,

i'd have definite use for those new functionality!

namespace sounds fine, and i'd prefer 'result' over futures or promises.

cheers

Nathan Wright

unread,
Jun 21, 2012, 5:12:35 AM6/21/12
to closure-lib...@googlegroups.com
This looks great! I've always been uncomfortable using goog.async.Deferred extensively because I haven't had the time to learn exactly how it works (especially chaining); its implementation is pretty complex. This API is easier to read and the implementation is dead simple. I like it a lot.

Have you guys given any thought to using "promise" as the namespace? In other words:

goog.promise.Result
goog.promise.wait
goog.promise.combine
goog.promise.chain
goog.promise.transform
etc...

This gives me an immediate sense of what is being combined, chained, waited on, etc. You return a promised result and you're chaining or transforming promises, it says right in the name. Meanwhile concurrent is perhaps less specific, but maybe that's a good thing if you want to include other new concurrency-related primitives there.

Thanks,
Nathan Wright

Dan Pupius

unread,
Jun 21, 2012, 11:46:58 AM6/21/12
to closure-lib...@googlegroups.com
"concurrent" seems a little odd for a single-threaded language.  Also, if these are intended to be core primitives throughout the library (as I hope) something shorter might be nice ;)

Nathan Naze

unread,
Jun 21, 2012, 1:27:28 PM6/21/12
to closure-lib...@googlegroups.com
> This looks great! I've always been uncomfortable using goog.async.Deferred extensively because I haven't had the time to learn exactly how it works (especially chaining); its implementation is pretty complex. This API is easier to read and the implementation is dead simple. I like it a lot.

Great, thank you for the feedback -- this is exactly what we were
trying to address with a simpler primative.

We'd like to move towards results as the primary primitive (with a
bridge back to deferreds for legacy use).

> "concurrent" seems a little odd for a single-threaded language.  Also, if
> these are intended to be core primitives throughout the library (as I hope)
> something shorter might be nice ;)

Yes, also our concern. We actually think "async" is a great namespace
but is, unfortunately, taken. Any other thoughts? (we'd been
fruitless)

Nathan

Garry Boyer

unread,
Jun 21, 2012, 1:40:46 PM6/21/12
to closure-lib...@googlegroups.com
I'm not necessarily a fan of this API. This looks too much like Java futures -- you have to explicitly remember whether what you're doing is chaining, composing, etc. I've always proposed having something like Deferred for Java, and my gut feeling is that this represents a step backwards. Deferred has significant simplicity in that it lets you adapt seamlessly between synchronous and asynchronous results. You can add a callback that returns undefined (and keeps the old value); you can add one that returns a new value; you can add a new one that blocks on another Deferred.

On the other hand, an API like this *may* be easier to *read* because it's more explicit, although it's much harder to write in. I guess that could be the saving grace, but I think it's too early to say it's ready to graduate. And also in the benefit of this API, a lot of people don't even realize the power of Deferred, because they're too used to Java-like programming with explicitness; those developers may see all the new constructs like chain and switch to them.

I'd appreciate a Docs form survey sent to folks who have to work regularly with Deferred and get a data driven result? :-)

Ivan Kozik

unread,
Jun 21, 2012, 2:21:11 PM6/21/12
to closure-lib...@googlegroups.com
On Thu, Jun 21, 2012 at 5:40 PM, Garry Boyer <gbo...@google.com> wrote:
> I'm not necessarily a fan of this API. This looks too much like Java futures
> -- you have to explicitly remember whether what you're doing is chaining,
> composing, etc. I've always proposed having something like Deferred for
> Java, and my gut feeling is that this represents a step backwards. Deferred
> has significant simplicity in that it lets you adapt seamlessly between
> synchronous and asynchronous results. You can add a callback that returns
> undefined (and keeps the old value); you can add one that returns a new
> value; you can add a new one that blocks on another Deferred.

For the same reasons, I'm also a fan of Deferred. I started using
them in Twisted, which had the first implementation. I use Closure's
Deferred quite a bit in my libraries Coreweb and Minerva[1] (I'll be
announcing them soon.) In Coreweb, I use them for a Twisted
Trial-like runner, where the runner can wait on the Deferred returned
from the test method. In Minerva, I expose Deferreds in an RPC-like
abstraction, allowing users to return a Deferred if they haven't
generated a response yet. I'm hoping that Deferred will stay as the
default async/promise abstraction, or at least still fully supported.

I'll just link to my favorite Deferred docs again, for anyone curious:

http://ezyang.com/twisted/defer2.html
http://twistedmatrix.com/documents/current/core/howto/defer.html
http://www6.uniovi.es/python/pycon/papers/deferex/ (glyph's original paper)

(The Closure Deferred is similar enough to the Twisted Deferred for
those docs to be useful, though there are a few differences.)

One way I like to wrap my mind around Deferreds: it provides
equivalent async control flow for all the synchronous control flow
(e.g. addBoth as an asynchronous try/finally). The beauty of
Deferreds is that they're fully composable in every way that'd you'd
expect.

Ivan

[1] BrowserChannel-like Comet server/client, http://ludios.org/minerva/

Nathan Naze

unread,
Jun 21, 2012, 2:28:08 PM6/21/12
to closure-lib...@googlegroups.com
So, just to touch on the Deferred vs Result debate -- we do not intend
to banish Deferreds. They are used too heavily today in existing code
to remove, and (as evidenced here), there are fans of both the
interactions of Deferreds and some of the special cases they cover.

Our goal is to have a simpler primitive for the common asynchronous
action case that's easier to pick up for those not intimately familiar
with Deferreds (they do have a non-trivial learning curve). But
because we know of the Deferreds' usage and existing users, we'd hope
to accommodate by providing the bridge/adapter (already in the source)
so that a simple Result object can be transformed to a Deferred if
need be, or if necessary given existing Deferred usages.

Make sense?

Nathan

Daniel Steigerwald

unread,
Sep 4, 2012, 7:21:56 PM9/4/12
to closure-lib...@googlegroups.com
goog.labs.result.waitOnSuccess -> goog.result.ok
goog.labs.result.waitOnError -> goog.result.fail
goog.labs.result.chain -> goog.result.chain
goog.labs.result.SimpleResult -> goog.result.Result
etc.

New async primitives are nice and well designed. Hope to see them in goog.* soon.

Dne čtvrtek, 21. června 2012 2:26:04 UTC+2 Vipul Bhasin napsal(a):

Kyaw

unread,
Sep 5, 2012, 7:18:10 AM9/5/12
to closure-lib...@googlegroups.com
There is no files in http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/labs/async/

What are the advantage of new API over goog.async.Deferred and DeferredList? I use it a lot in my database project. I don't see any feature missing in goog.async. It is also concise and easy to use.

Thanks,
Kyaw

Daniel Steigerwald

unread,
Sep 5, 2012, 4:17:52 PM9/5/12
to closure-lib...@googlegroups.com
and goog.labs.result.Result -> goog.result.IResult ofc.

Dne středa, 5. září 2012 1:21:56 UTC+2 Daniel Steigerwald napsal(a):
Reply all
Reply to author
Forward
0 new messages