> -----Original Message-----
> From: [email protected] [mailto:[email protected]]
> On Behalf Of Anne van Kesteren
> Sent: Wednesday, April 24, 2013 7:08 AM
> To: Ron Buckton
> Cc: Tab Atkins Jr.; es-discuss
> Subject: Re: Futures (was: Request for JSON-LD API review)
> 
> On Wed, Apr 24, 2013 at 1:16 AM, Ron Buckton <[email protected]>
> wrote:
> > * Future#then (tentatively adds the options argument in my proposal
> > for forcing synchronous execution of continuation)
> > * Future#done (tentatively adds the options argument in my proposal
> > for forcing synchronous execution of continuation)
> > * Future#catch (tentatively adds the options argument in my proposal
> > for forcing synchronous execution of continuation)
> 
> Why is that not up to the resolver? I think I'm missing something here.

In this case I am emulating a feature of .NET Tasks, similar to this: 
http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskcontinuationoptions.aspx.
 This allows the consumer of the future to make the determination as to whether 
their continuation should execute synchronously or asynchronously. From the 
MSDN documentation:

"Specifies that the continuation task should be executed synchronously. With 
this option specified, the continuation will be run on the same thread that 
causes the antecedent task to transition into its final state. If the 
antecedent is already complete when the continuation is created, the 
continuation will run on the thread creating the continuation. Only very 
short-running continuations should be executed synchronously."

This is often used to reduce the overhead of scheduling the continuation task 
if the continuation is very lightweight. I say "tentatively" as I am not sure 
if it's worth keeping, but I wanted to experiment with it a bit. It does allow 
for a bit of "cheating" though, as you can schedule a then/done synchronously 
to get the value synchronously if its available, so I might drop it if it has 
an adverse impact. I have found that it is helpful in the 
"cancellation-by-future" scenario, as if all scheduling is asynchronous it's 
difficult to properly time cancellation. For example:

function someAsync(canceler) {
  return new Future(function(resolver) {
    /*b*/ 
    var handle = setImmediate(function() {
      /*e*/
      resolver.resolve();
    });
    /*c*/ 
    if (canceler) canceler.done(function() { 
        /*f*/ 
        clearImmediate(handle); 
    });
  });
}

/*a*/
var cancelSource = new Deferred();
var future = someAsync(cancelSource.future);

/*d*/ 
cancelSource.resolve();

The order of events is:
Turn 0 (T0):
a. execution starts in the current turn (T0)
b. the setImmediate will schedule the callback on the event loop to be executed 
in turn T1. 
c. the continuation is added to the canceler during T0
d. the canceller is resolved during T0, continuations will be scheduled in T2

Turn 1 (T1):
e. the future from someAsync is resolved

Turn 2 (T2):
f. the continuation for canceler is executed, which is too late to cancel.

There are at least two solutions to this: 
1. Provide the ability to schedule the continuation at (c) synchronously 
(similar to .NET Tasks and the proposed options argument).
2. Provide the ability to resolve the canceler at (d) synchronously (possibly 
by exposing the "synchronous" flag in the DOM Futures spec to the developer).

Please note that "cancellation-by-future" is an alternative to providing either 
Future#cancel or some kind of Future.cancellable(init) -> { future, cancel }. I 
would still much rather have a formal Future#cancel both as a way to explicitly 
cancel a future and its chained descendants (since I may not care about the 
value of the Future anymore) as well as a way to provide cooperative 
cancelation.

> 
> 
> > * Future.of (extension. coerces thenables)
> > * Future.resolve
> 
> What would be the difference between these?

Future.resolve either accepts the value or resolves a Future, but not a 
"thenable" (e.g. it must be a branded Future, including cross-realm). Future.of 
is similar to Future.resolve but will coerce a "thenable" (though it ideally 
looks for a callable "done" if also present, to prevent the possible and 
unnecessary overhead of allocating a new "thenable". 

> 
> 
> > * Future.some (with properly ordered reject array value)
> > * Future.every (with properly ordered resolve array value)
> 
> These are now fixed in the specification.
> 
> I added the simple static completed future constructors
> (accept/resolve/reject). I'm waiting a bit with the library until there's more
> implementations and some feedback.
> 

I'm not yet sold on having both accept and resolve on the resolver.  In the 
.NET world, a Task for a Task (e.g. Task<Task<T>>) is just that, and you have 
to unwrap the Task with something like a TaskCompletionSource<T>, which is 
explicitly like FutureResolver#accept. Libraries like Q.js automatically assume 
a Future of a Future is just a Future, implicitly unwrapping like 
FutureResolver#resolve. When I started digging into Promise/Future for 
JavaScript a few years back I was primarily invested in the first camp due to 
my experience with Futures in a type-safe language. Actively using Futures in a 
dynamic language has pushed me more towards simplifying a nested Future into a 
single Future due to its simplicity. I can see how providing both mechanisms 
could possibly satisfy developers in either camp, but could be confusing to API 
consumers if one library generally uses FutureResolver#accept and another 
library generally uses FutureResolver#resolve.

Is there a lot of interest to support both, or any previous discussion on the 
topic that I could peruse to understand the arguments for having either 
"accept", "resolve", or both?

Thanks,
Ron

> 
> --
> http://annevankesteren.nl/

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to