-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Comparing ES Harmony Concurrency Strawman
Mark Miller and Kris Kowal (yours truly) are frequently experimenting and converging around Mark’s Concurrency Strawman for a future version of the ECMAScript specification. This is an analysis of the present (March 2012) differences between Q and the standard proposal.
-
High order bit: This Q implementation reflects nearly every “static”
Q.*(promise, …)
function as an equivalentpromise.*(…)
method. The only difference is that the static varieties always coerce the promise: values to fulfilled promises, thenables to wrapped promises, promiseSendables stay the same. I realize as I’m writing this that I should unconditionally wrap the given promise to guarantee the interface of the returned object, even in the face of malice. Giving promiseSendables a pass is a hazard. -
Resolve: Q does not support the proposed
Q()
function. The proposed behavior is equivalent to the presentQ.resolve()
as proposed by @domenic and the legacy (still supported)Q.ref()
as implemented in the original Waterkenref_send
on which Q is based. ThisQ
implementation providescall
andapply
methods for sending messages to promised functions. These would conflict withcall
andapply
on theFunction.prototype
. -
Reject: The
Q.reject(error)
function is implemented as proposed. I may eventually restrict the domain of the error to exception objects, or at least restrict strings, so that I can make some stronger guarantees to error handlers. -
isPromise: The
Q.isPromise
function is implemented as specified, as well asQ.isFulfilled
(which tolerates non-promise values),Q.isRejected
,Q.isResolved
as well as these functions as promise methods except **promise.isPromise()
. -
When/Then: Q does support
promise.when()
in the interest of compatibility with this specification, but thepromise.then()
interface has won over the JavaScript community. Q promises’then
method supports the CommonJS/A specification as proposed by Kris Zyp.Q.resolve(promise)
is also able to “assimilate” other objects that havethen
methods as long as they are designed to call the givenfulfilled
orrejected
functions; a property supported by Dojo promises and even the errant jQuery promises.Q.resolve(promise)
ignores the return-value of thethen
, ensuring that the assimilated promise is in-fact aQ
promise with all of the provided methods and behaviors. I recall that a colleague of Mark Miller found a reason why the method should be namedwhen
instead ofthen
, but I do not recall the argument and it has not surfaced a problem in my practice.The
end
function is implemented as specified, and also implemented asQ.end(promise)
.In addition, this implementation provides some shorthands:
promise.fail(errback)
andpromise.fin(finback)
.The
fail
function is a shorthand for passing only an errback tothen
. I may add support for a default noop errback. Presently, not providing an errback is the same as providing neither an errback nor a callback, which just forwards the resolution of the previous promise: which is to say it is an utterly useless pattern.
The ``finback`` receives no arguments, its fulfillment value is ignored — the resolution of the promise gets forwarded. However, if the finback returns a promise, the resolution of that promise may delay the forwarding. If the finback returns a promise that is eventually rejected, or if it throws an exception, the new error overrides the original resolution.
-
Get/Put/Post: The
get
,put
, andpost
are all implemented as proposed. The proposeddelete
is calleddel
inQ
, but experimentally aliased asdelete
.
The proposed ``promise.send`` is equivalent to the implemented ``promise.invoke``. I have reserved ``promise.send`` for sending messages to promises, but I have not documented it and the signature may be some combination of ``operator``, ``resolve``, and variadic arguments, where operators are like ``"get"`` and ``"del"``. I may change the ``"when"`` operator to ``"then"`` and ``"del"`` to ``"delete"``. I think there is some flexibility here still since it is only substantial to the protocol spoken between the Q and Q-Comm libraries. My operator names differ from Tyler Close’s original Waterken ref_send in that they are all lower-case.
-
Nearer Value: The proposed
Q.nearer(promise)
is almost equivalent to the implementedpromise.valueOf()
. If the promise is fulfilled,promise.valueOf()
returns the fulfilled value. If the promise is or has forwarded to a deferred promise, it returns most recently deferred promise (the specification says that it should return the original promise, but I presume this is not intentional). For rejected promises,promise.valueOf()
returns a sentinel object with{rejectedPromise: true, reason: {}}
; I intend to alter the implementation to meet the specification in this regard. -
All: The proposed
Q.all(...args)
is implemented as non-variadicQ.all(args)
. In the absence of rest arguments, we recover the cost of adding brackets in some places in not having to wrap promises likeQ.all.apply(null, promises)
in other cases. I’ve recently addedQ.allResolved(promises)
andpromiseForPromises.allResolved()
. -
Delay: I implemented
Q.delay
slightly differently. The proposal isQ.delay(millis, answer)
. To be consistent with other methods implemented both on theQ
object and on the promise object, this implementation puts the “answer” first, so the argument forms are:Q.delay(answer, millis)
,promise.delay(millis)
. For convenience, I recognize that when only one argument is provided (as indicated byarguments.length
), the answer is undefined,Q.delay(millies).then(function () {})
. -
Async: I have implemented
Q.async
as proposed, including support forReturnValue
errors as proposed for Harmony but not yet implemented in FireFox’s SpiderMonkey. -
Remotes and Vats: I have not implemented
makeFar
,makeRemote
,race
, orjoin
in this library. I have left these to the purview of Q-Comm. I would like to implement vats andwhere
(orthere
to be consistent withthen
) in WebWorkers and Node subprocesses uses ES5-Lab’s SES initializer. -
Others:* I also have not implemented
memoize
in this library since I do not want to entrain aWeakMap
shim.
I have also begun experimenting with the following keyword aliases:
-
finally
forfin
-
catch
forfail
(when(promise, void 0, callback)
) -
try
forcall
(e.g.,Q.try(f).catch(f).finally(f).end()
) -
delete
fordel