- From: Alex Russell <slightlyoff@google.com>
- Date: Wed, 5 Jun 2013 10:50:55 +0100
- To: Sean Hogan <shogun70@westnet.com.au>
- Cc: "www-dom@w3.org" <www-dom@w3.org>, "public-script-coord@w3.org" <public-script-coord@w3.org>, Anne van Kesteren <annevk@annevk.nl>
- Message-ID: <CANr5HFV4zFBbxt0G10cPMHHyYn0nKCYTjs_zDWwCUoUfh7bvPQ@mail.gmail.com>
On Saturday, May 18, 2013, Sean Hogan wrote:
> After more consideration I think I have some proposed changes which make
> Futures more consistent and flexible without compromising the current
> compatibility with JS Promise implementations.
>
> PRIMARY CHANGE:
>
> The primary change is the addition of two methods - call them `thenfu` and
> `catchfu` for now - which become the preferred methods for registering
> callbacks.
>
> `thenfu` and `catchfu` are similar to `then` and `catch` in that they are
> called with "accept" and/or "reject" callbacks and that they return a new
> Future.
>
> But they are also similar to the Future constructor in that the associated
> resolver is available to the callback (via `this`) as the intended means of
> resolving the future.
>
Adding the resolver for the generated future was discussed here:
https://github.com/slightlyoff/Futures/issues/46
The general consensus was that it can be added later if we like. I don't
see any need to expand the core contract for now.
> EXAMPLE:
>
> Using `thenfu` might look like this:
>
> new Future(function() {
> this.accept(2); // NOTE: `resolver` is `this`
> })
> .thenfu(function(value) { // immediate "accept"
> this.accept(value * value); // NOTE: `resolver` is `this`
> })
> .then(function(value) { // same thing as previous `thenfu`
> return value * value;
> })
> .thenfu(function(value) { // a delayed "accept" doesn't require
> another new Future
> var r = this;
> setTimeout(function() {
> r.accept(value * 2);
> });
> })
> .thenfu(function(value) { // Using `thenfu` with some JS Promise
> var promise = getExternalPromiseDependingOnMyValue(value);
> promise.then(this.accept, this.reject);
> })
> .thenfu(function(value) { // mapping async callback model to Futures
> var r = this;
> callAsyncFunction(value, function(err, result) {
> if (err) r.reject(err);
> else r.accept(result);
> }
> })
> .done(function(value) {
> console.log(value);
> });
>
>
> BENEFITS:
>
> The main benefits of this addition are:
>
> a. consistency in the way futures are initialized and resolved - that is,
> resolving is always asynchronous via `resolver.accept|reject`.
>
> b. easily mix with non-Promise asynchronous code without creating yet
> another a new Future
>
> c. `then` doesn't need to be the feature-test for Promise objects,
> and doesn't need to be a forbidden method of non-Promise objects.
>
>
> SECONDARY CHANGES:
>
> This addition necessitates and / or enables some secondary changes, most
> notably:
>
> a. the deprecation of `then` and `catch` from Future.
>
> b. the removal of `resolve` from FutureResolver.
>
> c. the modification of `new Future(init)` so that `resolver` becomes the
> `this` object of `init`.
>
> d. the requirement for `resolver.accept` and `resolver.reject` to be bound
> methods, thus enabling them to work when called as bare functions, for
> example:
>
> jsPromise.then(resolver.accept);
>
> e. It is also necessary to modify `Future.any|every|some` to not rely on
> `then` detection.
> More on that in a future post.
>
>
> INTEROPERABILITY:
>
> The advice to JS libs and devs wanting to **mix DOM Futures and Promises**
> is:
>
> 1. `then` and `catch` are deprecated.
>
> 2. Future objects may be passed to code expecting Promise-like objects
> with a `then` method.
>
> 3. If you call a future's `then` or `catch` then your callback must return
> a Promise-like object - that is, an object with a compatible `then` method.
>
> 3. If you call a future's `thenfu` or `catchfu` then your callback must
> use the provided resolver and can accept or reject by any procedure.
>
>
> ASIDE:
>
> `then` and `catch` can be simply implemented on top of `thenfu` and
> `catchfu`. For example, some rough JS code for `catch` would look like:
>
>
> Future.prototype.catch = function(onreject) { // NOTE: assume onreject
> is guaranteed a function
> this.catchfu(function(value) {
> try {
> var result = onreject(value);
> if (typeof result === 'object' && typeof result.then ===
> 'function') {
> result.then(this.accept, this.reject);
> }
> else this.accept(result);
> }
> catch(err) {
> this.reject(err);
> }
> });
> }
>
>
> The reverse is also trivial, but requires the creation of a new Future and
> tying it to the one already created by `catch`.
>
>
Received on Wednesday, 5 June 2013 09:51:26 UTC