- From: Sean Hogan <shogun70@westnet.com.au>
- Date: Sun, 19 May 2013 08:09:38 +1000
- To: www-dom@w3.org, "public-script-coord@w3.org" <public-script-coord@w3.org>
- CC: Anne van Kesteren <annevk@annevk.nl>
- Message-ID: <5197FC22.7020704@westnet.com.au>
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.
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 Saturday, 18 May 2013 22:10:18 UTC