- 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