Closed ForbesLindesay closed 11 years ago
A fuller example for the timeout
method that supports optional extensions like cancel
might look like:
var Promise = require('promise');
function timeout(promise, time) {
var assimilate = typeof promise.assimilate === 'function' ? promise.assimilate : Promise.from;
var res = Object.create(promise);
res.then = function (onFulfilled, onRejected) {
promise.then.apply(promise, arguments);
setTimeout(onRejected.bind(null, new Error('Operation Timed Out')), time);
};
return assimilate(res);
}
That's a pretty ugly timeout
compared to https://github.com/promises-aplus/resolvers-spec/issues/15#issuecomment-13362619; why?
Because yours doesn't handle:
thenable
without a promise.constructor
property or where that property does not point to a constructor with the correct signature.Mine has a fallback if the input promise does not support assimilation, propagates cancellation because Object.create
means we fall through to cancelling the input promise, passes all the arguments to the promises then
method, thereby ensuring that both rejection and progress are handled.
If you don't need any of these things then:
function timeout(promise, time) {
var Promise = promise.constructor;
return new Promise({ then: function (resolve, reject) {
promise.then(resolve, reject);
setTimeout(function () {
reject(new Error('Operation timed out.'));
}, time);
} });
}
seems to me no prettier than:
function timeout(promise, time) {
return promise.assimilate({ then: function (resolve, reject) {
promise.then(resolve, reject);
setTimeout(function () {
reject(new Error('Operation timed out.'));
}, time);
} })
}
And is functionally equivalent provided that promise
supports promise.assimilate
and promise.constructor
It's weird to use promise.assimilate
to produce a result that isn't related to promise
. In other words, it's weird to attach non-method functions to a promise.
I think assimilation is probably a (rare) use case that merits it though. If I'm a user of Q then an assimilate method on a Q promise seems odd because it has nothing to do with that promise. If I'm an author of a (promise library agnostic) library then an assimilate method on a Q promise seems fine, because it is related to that promise in that it's the way you create a promise of the same type as that promise.
Am I wrong or can assimiliate
completely replaced (shimmed?) with a then
call:
Promise.prototype.assimilate = function(maybeThenable) {
return this.then(function() {
return maybeThenable;
});
};
No, it can't be, because the promise this
refers to may never become fulfilled (or rejected) so that method is completely useful for building something like timeout
I think this is probably taken care of by a combination of the resolution procedure and the upcoming promise-creation spec. E.g.
var assimilated = new promise.constructor(resolve => resolve(valueToAssimilate));
Agree/disagree?
@domenic that looks right to me.
yep, that's fine with me.
I would like a repository to discuss Assimilation. I have made the following draft to get the ball rolling:
Assimilation/A+ - Draft A
This spec aims to specify a method for converting a
thenable
into a promise in the users preferred form (for libraries). A good use case for this is that of the utility functiontimeout
:It is not expected that all Promises/A+ promises will include this extension so if you want to support promise assimilation you should check for its support:
Motivation
Simple utility functions like
timeout
should ideally be written once and be usable independently of the users personal preference for promise library. As such, utility functions like timeout need to return functions of the same type that they take in as arguments. The simplest method for doing this is to allow libraries to assimilate their own promises into the correct promise type.Requirements: the
assimilate
methodA promise implementing this specification must have an
assimilate
method. Theassimilate
method must act as a function. i.e. the following are equivalentthenableArg
thenableArg
does not have athen
method (i.e.thenableArg && typeof thenableArg.then === 'function'
isfalse
)result
)result
is fulfilled withthenableArg
If
thenableArg
has athen
method (i.e.thenableArg && typeof thenableArg.then === 'function'
istrue
)result
)thenableArg.then
providing two arguments,onFulfiled
andonRejected
onFulfilled
is called,result
is fulfilled with the first argument ofonFulfilled
onRejected
is called,result
is rejected with the first argument ofonRejected
onProgress
, which should be used to fire progress handlers in a library specific way.thenableArg.then
must not be called until the call topromise.assimilate
has returned.Notes
Optionally, if the
thenableArg
has other methods such ascancel
these can be used as appropriate.